树
相关术语:
- root 根
- edge 边
- child 子节点
- parent 父节点
- leaf 叶节点
- sibling 兄弟节点
- path 路径:从节点n1 到 nk的路径定义为:节点n1 n2 n3 … nk 的序列, 使得对于1<=i<k的节点ni是ni+1的父节点。路径的长(length)即为该路径上的边的数量, 即k-1.
- depth
深度:从根节点到ni的唯一路径的长。特别的,根的深度为0. - internal path length 内部路径长:一棵树的所有节点的深度的和称为内部路径长。
- height 高度:从ni到一片树叶的最长路径的长。特别的,叶节点的高度都为0.
- height of tree 树的高度:即根节点的高度
- depth of tree 树的深度:即树的最深的节点的深度(树的深度=树的高度)
- ancestor 祖先
- descendant 后裔
- proper ancestor
- proper descendant
- preorder traversal 先序遍历:对节点的处理在对其子节点的处理之前
- postorder traversal 后序遍历:对节点的处理在对其子节点的处理之后
- inorder traversal 中序遍历:先处理左节点,再根节点,最后右节点(对于二叉树)
- level-order traversal 层序遍历:深度为D的节点要比深度为D+1的节点之前处理
相关结论:
- 高度为H的二叉树,最多有2^(H+1)-1个节点
- 深度为d的二叉树,最多有2^d个叶节点
- 具有L个叶节点的二叉树,至少是⌈logL⌉
- N个节点的二叉树中,存在N+1个空指针代表的N+1个子节点
- 满节点(full node) 是具有两个儿子的节点。满节点的个数 + 1 = 非空二叉树的叶节点的个数
-------------------->相关实现C++,放在GitHub了<--------------------
二叉查找树
结构性质
对于一个含有元素X的节点,其左节点的元素小于X,其右节点的元素大于X。
基本操作
平均运行时间都是O(logN)
Find
FindMin/FindMax
Insert
重复元素的插入可以通过在节点中附加一个用于指示重复次数的域。
Delete
- 对与叶节点,直接删除
- 只有一个子节点的节点:将其父节点中指向该节点的指针,指向该节点的子节点,从而绕过该节点。再删除。
- 有两个子节点的节点:用右子树的最小元素替代该节点,然后递归地删除那个节点。(右子树中的最小元素不可能有左子节点,所以第二次删除将是容易的).
(或用左子树中的最大节点代替该节点)
平衡树AVL树
结构性质
AVL树是带有平衡条件的二叉查找树,它保持树的深度是O(logN)。
一棵AVL树的每个节点的左子树和右子树的高度最多差1。
基本操作
Insert⭐
插入一个节点可能破坏AVL树的特性。树的特性被破坏后,可以通过旋转(rotation)来进行修正。
导致不平衡的四种情况:
- 对a节点的左子节点的左子树进行一次插入
- 对a节点的右子节点的右子树进行一次插入
- 对a节点的左子节点的右子树进行一次插入
- 对a节点的右子节点的左子树进行一次插入
- 前两中情况是互相对称的,发生在“外侧”,可以用一次 单旋转(single rotation)来完成调整
- 后两种情况是互相对称的,发生在“内侧”,可以用稍复杂的 双旋转(double rotation)来完成调整
- 插入后,一次旋转操作总是使整棵树的高度与原来树的高度相同,通向根节点的路径的高度不需要进一步的修正,因而总是只需要一次旋转操作
单旋转:
双旋转:
可以将Y当作是一个根k2和两颗子树B,C构成的子树。B或C中有一棵比D深两层(或者B,C,D都为空),即使不知到是那一颗也没关系,这不影响操作。
双旋转可以用两次单旋转来完成:
singleRotation(k1);
singleRotation(k3);
Delete⭐
执行完普通查找二叉树的删除操作后,在根节点到删除节点的路径上,检查需要旋转的子树并对其进行旋转。
伸展树SplayTree
结构性质
- 基本思想:当一个节点被访问后,要经过一系列AVL旋转树的旋转放到根上。
- 我们要在访问路径上的每一个节点和他们的父节点实施旋转,这会将被访问节点一直推向根。
基本操作
Find⭐
使用**展开(Splay)**实现将被访问的节点X推向根节点:
- 对访问路径上的每个点执行操作:
- 如果X的父节点是根,只接旋转X和根节点
- 否则说明其有祖父节点:
-
之字形(zig-zag)情形:X是右子节点,X的父节点是左子节点(以及对称的另一种情况)。执行一次双旋转
-
一字型(zig-zig)情形:X是左子节点,X的父节点也是左子节点(以及对称的另一种情况)。执行一次一字型旋转
(其实可以执行三次单旋转来完成,分别对singleRotation( P ) singlRotation(G) singleRotation(G)
-
实现原创:
- 递归地向下寻找时记录路径
- 递归返回时,返回所处理的节点与X节点的路径长
- 如果下一层递归返回上来的路径长为1,则说明该层递归所处理的节点与X节点的路径长为2,可以进行旋转操作,然后返回0
- 如果没由找到,则返回一个大于等于2的数,使旋转操作无法执行。
FindMin/FindMax
Insert
Delete
- 将该节点X旋转到根上。
- 删除该节点则得到左子树TL和右子树TR。
- 将TL中最大的元素旋转到TL的根上,此时,TL的没有右子节点。
- 使TR成为TL的根的右子节点,则完成删除。