Lec16 - Extends, Sets, Maps, and BSTs
Extends
从前,若一个类是接口的下位词,我们使用implements来书写方法的实现
但若想实现一个类是另一个类的下位词,我们需要使用extends
extends可以用于类与类、接口与接口之间
例:实现RotatingSLList
即让最后一个元素右旋到第一个元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package Lec16;
public class RotatingSLList<Item> extends SLList<Item> {
public void rotateRight(){
Item x = removeLast();
addFirst(x);
}
public static void main(String[] args){
RotatingSLList<Integer> rsl = new RotatingSLList<>();
rsl.addLast(10);
rsl.addLast(11);
rsl.addLast(12);
rsl.addLast(13);
rsl.rotateRight();
rsl.print();
}
}extends继承了SLList中的所有成员:
- 所有实例与静态变量
- 所有方法(除了构造函数)
- 所有嵌套类
但若成员是私有的就无法访问了
例:实现VengefulSLList
记录被删除的元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package Lec16;
import java.util.ArrayList;
import java.util.List;
public class VengefulSLList<Item> extends SLList<Item>{
private SLList<Item> deletedItems ;
public VengefulSLList(){
deletedItems = new SLList<Item>();
}
@Override
public Item removeLast(){
Item removedItem = super.removeLast(); // 使用父类的方法
deletedItems.addLast(removedItem);
return removedItem;
}
public void printLostItems(){
deletedItems.print();
}
public static void main(String[] args){
VengefulSLList<Integer> vsl = new VengefulSLList<>();
vsl.addLast(1);
vsl.addLast(5);
vsl.addLast(10);
vsl.addLast(15);
vsl.removeLast();
vsl.removeLast();
vsl.printLostItems();
}
}这里我们实现了对继承方法的重写
其中,我们可以使用super来调用父类中的方法
BST
随机表
链表的搜索效率较慢,我们可以在不同节点间随机额外添加一些链接,这样可以依赖随机性获得更好的效率
二叉搜索树的原理
若我们将每次搜索都折半,就能大幅提高效率,一个链表可以进行如下改造:
这是一棵二叉搜索树
二叉搜索树是一个有根的二叉树,对于书中的每个节点
- 左子树中的每个节点的值都小于该节点的值
- 右子树中的每个节点的值都大于该节点的值
寻找特定元素
- 若待寻找元素等于当前元素,返回
- 若待寻找元素小于当前元素,前往左子树寻找
- 若待寻找元素大于当前元素,前往右子树寻找
时间复杂度:\(\Theta(\log n)\)
因此搜索一颗完全BST的速度是很快的
1
2
3
4
5
6
7
8
9
10
static BST find(BST T, key sk){
if (T==null)
return null;
if (sk.equals(T.key))
return T;
else if (sk<T.key)
return find(T.left, sk);
else
return find(T.right, sk);
}添加元素
首先寻找待插入元素
- 若找到了就不进行操作
- 若没找到
- 创建一个新节点
- 创建合适链接
使用递归书写
1
2
3
4
5
6
7
8
9
static BST insert(BST T, key ik){
if (T==null)
return new BST(ik);
if (ik<T.key)
T.left = insert(T.left, ik);
else if (ik>T.key)
T.right = insert(T.right, ik);
return T;
}删除元素
删除没有孩子的节点:
直接删除,即将其父节点对应的左/右节点置空
删除一个孩子的节点:
要在维持BST性质的前提下删除:可以发现该节点的孩子一定大于(右侧)或小于(左侧)该节点
故我们可以寻找该节点的孩子,将指向它的节点指向他的孩子即可
删除两个孩子的节点:
找到左子树最大的节点或右子树最小的节点,替代待删除节点即可