树由节点(nodes)和边(edges)构成。整棵树有一个最上端节点,称为根节点(root)。每个节点可以有具方向性的边(directed edges),用来和其它节点相连。相连节点中,在上者为父节点(parent),在下者为子节点(child),无子节点者为叶节点(leaf)。子节点可以存在多个,如果最多只允许两个子节点,即所谓二叉树(binary tree)。不同结点如果拥有相同的父节点,则彼此互为兄弟节点(siblings)。根节点至任何节点之间有唯一途径(path),路径所经过的边数,称为路径长度(length)。根节点至任何一个节点的路径长度,即所谓该节点的深度(depth)。根节点的深度永远为0.某节点至最深子节点(叶节点)的路径长度,称为该节点的高度(height)。整棵树的高度,便以根节点的高度来表示。节点A->B之间如果存在(唯一)一条路径,那么A称为B的祖代(ancestor),B称为A的子代(descent)。任何节点的大小(size)是指其所有子代(包括自己)的节点总数。
二叉树搜索树(binary search tree)
二叉树,意义是任何节点最多只允许两个子节点,这两个子节点称为左子节点和右子节点。编译表达树(expression tree)和哈夫曼编码树(Huffman coding tree)都是二叉树。
二叉搜索树可提供对数时间的元素插入和访问。节点放置规则是:任何节点的键值一定大于其左子树中的每一个节点的键值,并小于右子树中每一个节点的键值。因此,从根节点一直往左走,直至无左路可走,即得最小元素,从根节点一直往右走,直至无右路可走,即得最大元素。
节点插入:从根结点开始,遇到键值较大则向左,遇到键值较小则向右,直到尾端,即插入点
节点删除:
- 无子节点,直接删除;
- 只有一个子节点,删除旧值,直接将其子节点连至其父节点;
- 有两个子节点,以右子树中的最小值取而代之(最小值可通过一直向左走到底获得)。
平衡二叉树(balanced binary search tree)
平衡的大致意义是:没有任何一个节点过深(深度过大)。
AVL树(Adelson-Velskii-Landis tree)
平衡因子:节点的左子树深度减去右子树深度。
要求:任何节点的左右子树高度相差最多为1。
平衡被破坏情况:设最深节点为X,X的左右两棵子树的高度相差2,即平衡因子绝对值大于1,分四种情况
- 插入点位于X的左子节点的左子树-左左;
- 插入点位于X的左子节点的右子树-左右;
- 插入点位于X的右子节点的左子树-右左;
- 插入点位于X的右子节点的右子树-右右。
1,4情况彼此对称,称为外侧插入,可采用单旋转操作调整解决;2,3情况彼此对称,称为内侧插入,可采用双旋转操作调整解决。
单旋转
情况1:以X为支点右旋
// a b
// / \ / \
// b ar bl a
// / \ ---> / / \
// bl br c br ar
// /
// c
//待插入节点为c,为情况1,需要进行右旋操作
void RRotate(BiTree& a)
{
b = a->left;
a->left = b->right;
b->right = a;
a->height = Max(Height(a->left), Height(a->right));
b->height = Max(Height(b->left), Height(b->right));
return b;
}
情况4:以X为支点左旋
// a b
// / \ / \
// al b a br
// / \ ---> / \ \
// bl br al bl c
// \
// c
//待插入节点为c,为情况4,需要进行左旋旋操作
void LRotate(BiTree& a)
{
b = a->right;
a->right = b->left;
b->left = a;
a->height = Max(Height(a->left), Height(a->right));
b->height = Max(Height(b->left), Height(b->right));
return b;
}
情况2,情况3:
// a a c
// / \ / \ / \
// b ar c ar b a
// / \ / \ /\ /\
// bl c ----> b cr ----> bl d cr ar
// / \ / \
// d cr bl d
//待插入节点为d,为情况2,需要进行双旋转操作,先对a.left进行左旋,再对a进行右旋
void LRRotate(BiTree& a)
{
a->left = LRotate(a->left);
return RRotate(a);
}
// a a c
// / \ / \ / \
// al b al c a b
// / \ / \ / \ / \
// c br ----> d b ----> al d cr br
// / \ / \
// d cr cr br
//待插入节点为d,为情况3,需要进行双旋转操作,先对a.right右旋,再对a左旋
void RRRotate(BiTree& a)
{
a->right = RRotate(a->right);
return LRotate(a);
}