树与二叉树的应用
1.二叉排序树的应用
1.1、定义
二叉排序树(也称二叉查找树)或者是一颗空树,或者是一颗具有下列特性的非空二叉树:
1. 若左子树非空,则左子树上所有节点关键字值均小于根节点的关键字值。 2. 若右子树非空,则右子树上所有节点关键字值均大于根节点的关键字值。 3. 左、右子树本身也分别是一颗二叉排序树。
(ps:二叉排序树是一个递归的数据结构,且左子树节点值<根节点值<右子树节点值。由中序遍历可以得到一个递增的有序序列。)
- 特点:二叉排序树是一种动态集合,树的结构通常不是一次生成的,而是在查找过程中,当树中不存在关键字值等于给定值得结点时再进行插入的。
1.2、基本操作
- 1.2.2插入
若原二叉树排序树为空,则直接插入结点;
若关键字k小于根结点关键字,则插入左子树;
若关键字k大于根结点关键字,则插入右子树;
此为递归定义int BST_Insert(BiTree &T, KeyType k){
// 在二叉排序树T中插入一个关键字为k的结点
if(T==NULL){
T = (BiTree)malloc(sizeof(BSTNode));
T->key = k;
T->lchild=T->rchild=NULL;
return 1; // 返回1,表示成功
}else if(k==T->key) // 树中存在相同关键字的结点
return 0;
else if(k<T->key) // 插入T的左子树
return BST_Insert(T->lchild, k);
else // 插入T的右子树
return BST_Insert(T->rchild, k);
}
- 1.2.2构造
每读入一个元素,就建立一个新结点,若二叉排序树非空,则将新结点的值与根结点的值比较,若小于根结点的值,则插入左子树,否则插入右子树;若二叉排序树为空,则将新结点作为二叉排序树的根结点。
void Creat_BST(BiTree &T, KeyType str[], int n){
// 用关键字数组str[]建立二叉排序树
T = NULL; // 初始化bt为空树
int i = 0;
while(i < n){ // 依次将每个元素插入
BST_Insert(T, str[i]);
i++;
}
}
- 1.2.4查找
查找是从根结点开始,沿某个分支逐层向下进行比较的过程。
若二叉排序树非空,则将关键字与根结点的关键字比较,若相等,则查找成功;
若不等,则当根结点的关键字值大于给定关键字值时,在根结点的左子树中查找,否则在根结点的右子树中查找。
// 非递归查找
BSTNode *BST_Search(BiTree T, ElemType key, BSTNode *&p){
// 查找函数返回指向关键字值为key的结点指针,若不存在,返回NULL;
p = NULL; // p指向被查找结点的双亲,用于插入和删除操作中
while(T!=NULL&&key!=T->data){
p = T;
if(key<T->data) T=T->lchild;
else T = T->rchild;
}
return T;
}
- 1.2.3删除
删除操作的实现过程按3种情况来处理:
1.若被删除结点z是叶结点,则直接删除,不会破坏二叉排序树的性质。
2.若结点z只有左子树或右子树,则让z子树成为z父结点的子树,代替z的位置。
3.若结点z有左、右两颗子树,则令z直接后继(后直接前驱)替代z,然后从二叉排序树中删除这个直接后继(或直接前驱),这样就转换成为了第一或第二种情况。
- 1.2.5查找效率分析
二叉排序树查找算法的平均查找长度,主要取决于树的高度。
2.平衡二叉树
2.1、定义
在插入和删除二叉树结点时,要保证任意结点的左、右子树高度差的绝对值不超过1,这样的二叉树称为平衡二叉树(Balanced Binary Tree),简称平衡树(AVL)。
目的:避免树的高度增长过快,而导致降低了二叉排序树的性能。
平衡因子:结点左子树与右子树的高度差。
2.2、基本操作1
- 2.2.1 插入/删除
基本思想:每当在二叉排序树中插入(或删除)一个结点时,首先检查其插入路径上的结点是否因为此次操作而导致了不平衡。若导致了不平衡,则先找到插入路径上离插入结点最近的平衡因子的绝对值大于1的结点A,再对以A为根的子树,在保持二叉排序树特性的前提下,调整各结点的位置关系,使之重心达到平衡。
失去平衡后进行调整的规律如下:
1)LL平衡旋转(右单旋转)
2)RR平衡旋转(左单旋转)
3)LR平衡旋转(先左后右双旋转)
4)RL平衡旋转(先右后左双旋转)
- 2.2.2查找
3.哈夫曼树和哈夫曼编码
3.1、定义
树中 结点常常被赋予一个表示某种意义的数值,称为该结点的权。从树根结点到任意结点的路径长度(边数)与该结点上权值的乘积,称为该结点的带权路径长度。树中所有叶结点的带权路径长度之和称为该树的带权路径长度。
其中带权路径长度最小的二叉树称为哈夫曼树,也称为最优二叉树。
3.2、哈夫曼树的构造
- 1、將n个结点分别作为n棵仅含一个结点的二叉树,构成森林F.
- 2、构造一个新结点,从F中选取两棵根结点权值最小的树作为新结点的左、右子树,并且将新结点的权值置为左右子树上根结点的权值之和。
- 3、从F中删除刚才选出的两棵树,同时将新得到的树加入F中。
- 4、重复步骤2、3,直到F中只剩下一颗树为止。
3.3、哈夫曼编码
哈夫曼编码是一种可变长度编码,应用于数据压缩编码。
- 首先,将每个出现的字符当做一个独立的结点,权值为它出现的频度(或次数),构造出对应的哈夫曼树。
- 将字符的编码解释为从根至该字符的路径上边标记的序列,其中边标记为0表示"转向左孩子",标记为1表示"转向右孩子"。