3.二叉树排序法
-
定义:二叉排序树或者是一棵空树;或者是具有如下特性的二叉树:
- 若它的左子树不空,则左子树上所有结点的值均小于根结点的值;
- 若它的右子树不空,则右子树上所有结点的值均大于根结点的值;
- 它的左,右子树也都分别是二叉排序树。
-
二叉排序树的定义是一个递归定义的过程。
- 以根结点作为分界点。
- 将二叉树的左子树上的结点和右子树上的结点区分开。
- 保证小于根结点值得结点都落在左子树上。
- 而大于根结点值的结点都落在右子树上。
-
二叉排序树:
- 若二叉排序树为空,则查找失败;
- 若给定值等于根结点的关键字,则查找成功;
- 若给定值小于根结点的关键字,则继续在左子树上进行查找;
- 若给定值大于根结点的关键字,则继续在右子树上进行查找;
-
整个查找过程生成了一条查找路径:
- 从根结点出发,沿着左分支或者右分支逐层向下直至关键字等于给定值的结点;-------查找成功。
- 从根结点出发,沿着左分支或者右分支逐层向下直至至真指向空树为之。----------查找失败。
-
查找算法实现(尾递归):
BSTree SearchBST(BSTree bst,KeyType key){ if(!bst) return NULL; else if(bst->key==key) return bst; else if(key<bst->key) return SearchBST(bst->lchild,key); else return SearchBST(bst->rchild,key); }
-
二叉排序树的插入
- 在二叉排序树中插入结点的位置,恰好是我们查找失败的位置。
- 如果二叉排序树为空,则新插入的结点为新的根结点;否则,新插入的结点必为一个新的叶子结点,其插入位置由查找过程得到。
-
算法:
void InsertBST(BSTree *bst,KeyType key){ BiTree s; if(*bst==NULL){ s=(BSTree)malloc(sizeof(BSTNode)); s->key = key; s->lchild=NULL; s->rchild=NULL; *bst = s; } else if(key<(*bst)->key) InsertBST(&((*bst)->lchild),key); else if(key>(*bst)->key) InsertBST(&((*bst)->rchild),key); }
-
二叉排序树生成:
-
二叉排序树生成算法
-
例如:设关键字输入顺序为:45,24,53,12,28,90
-
将45作为根结点,然后按照二叉树规律插入
-
调换关键字后:24,45,53,90,12,28
-
同样的关键字,不同的输入顺序,得到的二叉排序树的形态不同。
-
二叉排序树的形态完全由一个输入序列决定,一个无序序列可以通过构造一棵二叉排序树而得到一个有序序列。
-
算法:
void CreateBST(BSTree *bst){ KeyType key; *bst = NULL; scanf("%d",&key); while(key!=ENDKEY){ InsertBST(bst,key); scanf("%d",&key); } }
-
- 对其进行中序遍历,得到一个序列:10,20,23,25,30,35,40,48
- 特点:
- 中序遍历二叉排序树可得到关键字有序序列
- 在构造二叉排序树时,每次插入的新结点都是新的叶子结点,所以进行插入时不必移动其他结点。
- 二叉排序树不但拥有类似于折半查找的特性,又采用了链表作存储结构,因此是动态查找表的一种适宜表示。
-
-
二叉排序树的删除算法
-
与插入相反,删除在查找成功之后进行,并且要求在删除二叉排序树上某个结点之后,仍然保持二叉排序树的特性。
-
分为三种情况:
-
被删除的结点是叶子;
- 解决方案:调整其相应的父节点为空即可。
-
被删除的结点只有左子树或者只有右子树;
- 解决方案:将其对应的双亲结点的指针域进行调整,其双亲结点的相应指针域的值改为“指向被删除结点的左子树或右子树。”
-
被删除的结点既有左子树,也有右子树。
- 解决方案:以其前驱或后继替代之,然后再删除该前驱或后继结点。
-
-
算法的实现:
BSTNode *DelBST(BSTree t,KeyType k){ BSTNode *p,*f,*s,*q; p=t; f=NULL; while(p){ if(p->key==k) break; f=p; if(p->key>k) p=p->lchild; else p=p->rchild; } if(p==NULL) return t; if(p->lchild==NULL){ if(f==NULL) t=p->rchild; else if(f->lchild==p) f->lchild=p->rchild; else f->rchild=p->rchild; free(p); } else{ q=p; s=p->lchild; while(s->rchild) { q=s; s=s->rchild; } if(q==p) q->lchild=s->lchild; else q->rchild=s->lchild; p->key=s->key; free(s); } return t; }
-
-
性能分析:
- 最差的情况就是单支树,与顺序查找相同;
- 最好的情况是与折半查找判定树相同。
-
二叉排序树的特点:
- 中序遍历二叉排序树可以得到关键字的有序序列。
- 在构造二叉排序树的时候,不需要移动其他结点。
- 二叉排序树可以得到折半查找一样好的实践性能并且由于它是链式存储所以二叉排序树的插入和删除相对的元素移动量都是非常少的。