[算法导论]第十二章《二叉搜索树》
来源:互联网 发布:最优化方法例题 编辑:程序博客网 时间:2024/05/14 03:39
一、概念
1.定义与性质
(1)设x为二叉查找树中的一个结点,若y是x左子树中的一个结点,则key[y] <= key[x];若y是x右子树中的一个结点,则key[x]<=key[y](2)二叉查找树上执行的基本操作的时间与树的高度成正比。
2.结构
(1)结点结构:
关键字key卫星数据data
分别指向父、左右孩子的指针p, left, right
3.在二叉查找树上的操作
查找一个关键字:SEARCH(x, k)求最小关键字:MINIMUM(x)
求最大关键字:MAXIMUM(x)
求前驱:PREDECESSOR(x)
求后继:SUCCESSOR(x)
插入一个结点:INSERT(T, z)
删除一个结点:DELETE(z)
4.二叉查找树的应用
1.遍历:中序遍历、先序遍历、后序遍历2.查找:查找包含某个关键字的结点,查找关键字最大或最小的结点、查找某个结点的前驱或后继
一棵二叉树查找及其中根遍历结果如下图所示:
(1)查找
在二叉查找树中查找一个给定的关键字k的过程与二分查找很类似,根据二叉查找树在的关键字存放的特征,很容易得出查找过程:首先是关键字k与树根的关键字进行比较,如果k大比根的关键字大,则在根的右子树中查找,否则在根的左子树中查找,重复此过程,直到找到与遇到空结点为止。例如下图所示的查找关键字13的过程:(查找过程每次在左右子树中做出选择,减少一半的工作量)
书上查找过程的递归和非递归形式的伪代码:
TREE_SEARCH(x,k) if x=NULL or k=key[x] then return x if(k<x.key) then return TREE_SEARCH(x.left,k) else then return TREE_SEARCH(x.right,k)
ITERATIVE_TREE_SEARCH(x,k) while x!=NULL and k!=x.key do if k<x.key then x=x.left else then x=x.right return x
(2)查找最大关键字和最小关键字
根据二叉查找树的特征,很容易查找出最大和最小关键字。查找二叉树中的最小关键字:从根结点开始,沿着各个节点的left指针查找下去,直到遇到NULL时结束。如果一个结点x无左子树,则以x为根的子树中,最小关键字就是key[x]。查找二叉树中的最大关键字:从根结点开始,沿着各个结点的right指针查找下去,直到遇到NULL时结束。书中给出了查找最大最小关键字的伪代码:
TREE_MINMUM(x) while x.left != NULL do x=x.left return x
TREE_MAXMUM(x) while x.right != NULL do x= x.right return x
(3)前驱和后继
查找前驱步骤:先判断x是否有左子树,如果有则在left[x]中查找关键字最大的结点,即是x的前驱。如果没有左子树,则从x继续向上执行此操作,直到遇到某个结点是其父节点的右孩子结点。例如下图查找结点7的前驱结点6过程:
查找后继步骤:先判断x是否有右子树,如果有则在right[x]中查找关键字最小的结点,即使x的后继。如果没有右子树,则从x的父节点开始向上查找,直到遇到某个结点是其父结点的左儿子的结点时为止。例如下图查找结点13的后继结点15的过程:
书中给出了求x结点后继结点的伪代码:
TREE_PROCESSOR(x) if x.right != NULL then return TREE_MINMUM(x.right) y=x.p while y!= NULL and x ==y.right do x = y y=y.p return y
定理:对一棵高度为h的二叉查找,动态集合操作SEARCH、MINMUM、MAXMUM、SUCCESSOR、PROCESSOR等的运行时间均为O(h)。
3、插入和删除
插入和删除会引起二叉查找表示的动态集合的变化,难点在在插入和删除的过程中要保持二叉查找树的性质。插入过程相当来说要简单一些,删除结点比较复杂。
(1)插入
插入结点的位置对应着查找过程中查找不成功时候的结点位置,因此需要从根结点开始查找带插入结点位置,找到位置后插入即可。下图所示插入结点过程:
书中给出了插入过程的伪代码:
TREE_INSERT(T,z) y = NULL; x =T.root while x != NULL do y =x if z.key < z.key then x=x.left else x=x.right z.p =y if y=NULL then T.root =z else if z.key>y.key then y.left = z else y.right =z
插入过程运行时间为O(h),h为树的高度。
(2)删除
从二叉查找树中删除给定的结点z,分三种情况讨论:
<1>结点z没有左右子树,则修改其父节点p[z],使其为NULL。删除过程如下图所示:
<2>如果结点z只有一个子树(左子树或者右子树),通过在其子结点与父节点建立一条链来删除z。删除过程如下图所示:
<3>如果z有两个子女,则先删除z的后继y(y没有左孩子),在用y的内容来替代z的内容。
书中给出了删除过程的伪代码:
TREE_DELETE(T,z) if z.left ==NULL or z.right == NULL then y=z else y=TREE_SUCCESSOR(z) if y.left != NULL then x=y.left else x=y.right if x!= NULL then x.p = y.p if y.p ==NULL then Troot =x else if y = y.p.left then y.p.left = x else y.p.right =x if y!=z then z.key = y.key copy y's data into z return y
定理:对高度为h的二叉查找树,动态集合操作INSERT和DELETE的运行时间为O(h)。
代码的C++实现:
/* *作者:RogerKing *邮箱: jin_tengfei@163.com *日期:2014-03-19-10.15 */#include <iostream>using namespace std;typedef struct TreeNode{int key;TreeNode*left;//左孩子TreeNode*right;//右孩子TreeNode*pre;//指向父节点的指针}*TreePoint;/*************12.1二叉搜索树*****************************///递归的中序遍历void Inorder_Tree_Walk(TreePoint x){if (x!=NULL){//中序遍历当前结点的左子树Inorder_Tree_Walk(x->left);//访问当前结点cout<<x->key<<" ";//中序遍历当前结点的右子树Inorder_Tree_Walk(x->right);}}/*************12.2查询二叉搜索树*************************///递归查询二叉搜索树TreePoint Tree_Search(TreePoint x,int k){//找到叶子结点了还没找到,或当前结点是所查找的结点if(x==NULL||x->key==k)return x;//所查找的结点位于当前结点的左子树if (k<x->key)return Tree_Search(x=x->left,k);//所查找的结点位于当前结点的左子树elsereturn Tree_Search(x=x->right,k);}//非递归查询二叉搜索树TreePoint Iterative_Tree_Search(TreePoint x,int k){//不是叶子结点且不是所查找的结点 while (x!=NULL&&x->key!=k) {//所查找的结点位于当前结点的左子树 if (k<x->key)x=x->left; //所查找的结点位于当前结点的右子树else x=x->right; } return x;}//查找树中最小元素TreePoint Tree_Minimum(TreePoint x){while (x->left){x=x->left;}return x;}//查找树中最大元素TreePoint Tree_Maximum(TreePoint x){while (x->right){x=x->right;}return x;}//查找某个节点中序遍历情况下的后继节点,后继是大于key[x]的最小的结点TreePoint Tree_SUCCESSOR(TreePoint x){if(x == NULL) { return NULL; }//如果右子树不为空,则后继为其右子树的最小值节点else if (x->right!=NULL){return Tree_Minimum(x->right);}TreePoint y=x->pre;while (y!=NULL&&x==y->right){x=y;y=y->pre;}return y;}//查找某个节点中序遍历情况下的前驱节点,前驱是小于key[x]的最大的结点 。TreePoint Tree_Predecessor(TreePoint x){ if(x == NULL) { return NULL; }//如果左子树不为空,则前驱为其左子树的最大值节点 else if(x->left != NULL) { return Tree_Maximum(x->left); } TreePoint t=x->pre; while((t != NULL) && (x == t->left)) {x = t;t = t->pre;}return t;}/*************12.3插入和删除*****************************///采用循环而非递归的插入树节点。void Tree_Insert(TreePoint& T,int key){TreePoint x=T,y=NULL,z = new TreeNode;z->key=key;z->left=z->right=z->pre=NULL;//树中有节点时找到插入节点需要插入的位置while (x!=NULL){y=x;if (key<x->key){x=x->left;}elsex=x->right;}z->pre=y;if (y==NULL)//树为空时{T=z;}else{if (key<y->key){y->left=z;}else{y->right=z;}}}//二叉搜索树的删除void Tree_Delete(TreePoint root,TreePoint z){TreePoint x=NULL,y;//若z最多只有一个孩子,实际删除的结点是zif (z->left==NULL||z->right==NULL)y=z;//若z有两个孩子,实际删除的结点是z的后继elsey=Tree_SUCCESSOR(z);//用x表示"实际要删除的结点"的孩子(最多一个孩子)if (y->left!=NULL)x=y->left;elsex=y->right;//修改指针,以删去结点if (x!=NULL)//若"实际要删除的结点"没有孩子x->pre=y->pre;if (y->pre==NULL)//若"实际要删除的结点"是根结点root=x;else if (y==y->pre->left) y->pre->left=x; else y->pre->right=x;//"若初阶要删除的结点"不是"待删除的结点",则内容替代if (y!=z)z->key=y->key;}int main(){TreePoint root=NULL;int a[14]={15,5,26,35,2,20,17,3,18,24,6,1,10,7};for (int i=0;i<14;i++){Tree_Insert(root,a[i]);}cout<<"中序遍历树结果\n";Inorder_Tree_Walk(root);cout<<endl;cout<<"插入元素:19 ";Tree_Insert(root,19);cout<<endl;cout<<"插入元素后中序遍历树结果\n";Inorder_Tree_Walk(root);cout<<endl;cout<<"查找元素15:";TreePoint p=Tree_Search(root,15);if (p){cout<<"已经找到元素 \n";}elsecout<<"没有找到元素 \n";cout<<"元素15的前驱节点:";cout<<Tree_Predecessor(p)->key<<" "<<(Tree_Predecessor(p) != NULL ? "查找成功" : "查找失败")<<endl;p=Tree_Search(root,20);cout<<"元素20的后继节点:";cout<<Tree_SUCCESSOR(p)->key<<" "<<(Tree_SUCCESSOR(p) != NULL ? "查找成功" : "查找失败")<<endl;cout<<"删除树中值为10的元素\n";p=Tree_Search(root,10);Tree_Delete(root,p);Inorder_Tree_Walk(root);cout<<endl;return 0;}
结果显示:
- [算法导论]第十二章《二叉搜索树》
- 算法导论 第十二章 二叉搜索树
- 算法导论第十二章-二叉搜索树-Cpp代码实现
- 算法导论第十二章__二叉搜索数
- 算法导论第十二章:二叉查找树
- 算法导论(Introduction to Algorithms )— 第十二章 二叉搜索树— 12.1 什么是二叉搜索树
- 算法导论 12章 二叉搜索树
- 算法导论 12章 二叉搜索树
- 《算法导论》学习笔记--第十二章 二叉查找树
- 算法导论第十二(12)章 二叉查找树
- 算法导论 第十二章:二叉查找树(Binary Search Trees)
- 算法导论-----二叉搜索树
- 算法导论-----------二叉搜索树
- 算法导论 二叉搜索树
- 算法导论--二叉搜索树
- 【算法导论】二叉搜索树
- 算法导论二叉搜索树
- 算法导论 二叉搜索树
- Ubuntu12.04安装JAVA
- 第七章 MVC模式与视图间传值
- 组合索引避免索引扫描后在过滤
- ios学习临时笔记-CGContext学习
- 一步步学习SPD2010--第十三章节--管理SP Server环境的Web内容(2)--理解SP Server2010的Web内容管理
- [算法导论]第十二章《二叉搜索树》
- 1075(hdu)
- 引用Interop.SQLDMO.dll后的注意事项。
- php解析xml详细介绍
- 在VB和VB.NET程序中判断当前是否运行于开发环境中
- Android 分析监听器上的参数position和id
- 2013 蓝桥杯 C.B组 07题(ungetc函数的应用)
- 名词解释
- 腾讯、百度、网易游戏、华为Offer及笔经面经