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 19
| 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
随机表
链表的搜索效率较慢,我们可以在不同节点间随机额外添加一些链接,这样可以依赖随机性获得更好的效率
二叉搜索树的原理
若我们将每次搜索都折半,就能大幅提高效率,一个链表可以进行如下改造:
这是一棵二叉搜索树
二叉搜索树是一个有根的二叉树,对于书中的每个节点
- 左子树中的每个节点的值都小于该节点的值
- 右子树中的每个节点的值都大于该节点的值
寻找特定元素
- 若待寻找元素等于当前元素,返回
- 若待寻找元素小于当前元素,前往左子树寻找
- 若待寻找元素大于当前元素,前往右子树寻找
时间复杂度:
因此搜索一颗完全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性质的前提下删除:可以发现该节点的孩子一定大于(右侧)或小于(左侧)该节点
故我们可以寻找该节点的孩子,将指向它的节点指向他的孩子即可
删除两个孩子的节点:
找到左子树最大的节点或右子树最小的节点,替代待删除节点即可