二叉排序(查找,搜索)树详解
2017-10-22 16:24
190 查看
二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有结点的值均小于或等于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
一,储存方式
按二叉树的存储方式,定义一个结构体,包含节点的值,指向左右子树的指针;
二,初始化函数
先通过while循环找到要插入节点p的前驱q的位置,并判断p应插入q的左还是右子结点;
如果是空树即Root==NULL,则Root指向p;
三,排序
因为二叉排序树的每一个结点都大于其左子树,小于其右子树,那么对其进行中序遍历即可得到递增序列
四,查找
简单,无需解释,直接上代码
五,删除结点(难点)
删除结点要保证删除后的树仍然为一颗二叉查找树,即每一个结点都大于其左子树,小于其右子树;
理论上分为三种情况:
(1)要删除的结点为叶子结点(无左右子数);
直接删除;
(2)要删除的结点有左子树或者有右子树;
将要删除结点的左子树或者右子树变为要删除结点前驱(双亲)的左子树或者右子树,并删除结点;
(3)有左右子树;
用左子树中最大的数取代要删除结点的值并删除最大数所在的结点
或者用右子树中最小的数代替要删除结点的值并删除最下的数所在的结点;
实际实现:
(一)无左子树;
(1)是根节点:根节点直接指向其右子树;
(2)不是根节点:若要删除的结点为其前驱结点(双亲结点)的左子结点,其前驱结点(双亲结点)的左子节点指向要删除结点的左子节点,若要删除结点为其前驱结点(双亲结点)的右子结点,其前驱结点(双亲结点)的右子结点指向要删除结点的左子节点。
(二)有右子树;
用左子树中最大的数取代要删除结点的值并删除最大数所在的结点,因为每个结点都小于其右子结点,所以最大的数所在的结点无右子结点,而其左子树也是最大数所在结点的前驱结点(双亲结点)的右子树的一部分(都大于双亲结点的值)所以如果最大值所在的结点有左子树的话,直接把其左子树接到其前驱结点(双亲结点)的右子结点;
具体代码:
(1)若左子树不空,则左子树上所有结点的值均小于或等于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
一,储存方式
按二叉树的存储方式,定义一个结构体,包含节点的值,指向左右子树的指针;
typedef struct treeNode{ int x; struct treeNode *lchild,*rchild; }BSTree;
二,初始化函数
BSTree *BSTreeInsert(BSTree *Root,int n){ BSTree *q,*p=Root; while(p){ q=p; if(p->x>n)p=p->lchild; else p=p->rchild; } p=(BSTree*)malloc(sizeof(BSTree)); p->x=n; p->lchild=p->rchild=NULL; if(Root==NULL)Root=p; else if(q->x>n)q->lchild=p; else q->rchild=p; return Root; } BSTree *CreatBSTree(int a[],int n){ BSTree *Root=NULL; int i=0; while(i<n){ Root=BSTreeInsert(Root,a[i]); i++; } return Root; } int main(){ int a[5]={23,1,45,8,12}; BSTree* Root=CreatBSTree(a,5); return 0; }采用一个个插入的方法构建;
先通过while循环找到要插入节点p的前驱q的位置,并判断p应插入q的左还是右子结点;
如果是空树即Root==NULL,则Root指向p;
三,排序
因为二叉排序树的每一个结点都大于其左子树,小于其右子树,那么对其进行中序遍历即可得到递增序列
void display(BSTree* Root){ if(Root){ display(Root->lchild); cout<<(Root->x)<<" "; display(Root->rchild); } }
四,查找
简单,无需解释,直接上代码
BSTree* BSTreeSerch(BSTree* Root,int k){ if(Root==NULL)return NULL; else{ while(Root!=NULL){ if(k==Root->x)return Root; else if(k>Root->x)Root=Root->rchild; else Root=Root->lchild; } } return NULL; }
五,删除结点(难点)
删除结点要保证删除后的树仍然为一颗二叉查找树,即每一个结点都大于其左子树,小于其右子树;
理论上分为三种情况:
(1)要删除的结点为叶子结点(无左右子数);
直接删除;
(2)要删除的结点有左子树或者有右子树;
将要删除结点的左子树或者右子树变为要删除结点前驱(双亲)的左子树或者右子树,并删除结点;
(3)有左右子树;
用左子树中最大的数取代要删除结点的值并删除最大数所在的结点
或者用右子树中最小的数代替要删除结点的值并删除最下的数所在的结点;
实际实现:
(一)无左子树;
(1)是根节点:根节点直接指向其右子树;
(2)不是根节点:若要删除的结点为其前驱结点(双亲结点)的左子结点,其前驱结点(双亲结点)的左子节点指向要删除结点的左子节点,若要删除结点为其前驱结点(双亲结点)的右子结点,其前驱结点(双亲结点)的右子结点指向要删除结点的左子节点。
(二)有右子树;
用左子树中最大的数取代要删除结点的值并删除最大数所在的结点,因为每个结点都小于其右子结点,所以最大的数所在的结点无右子结点,而其左子树也是最大数所在结点的前驱结点(双亲结点)的右子树的一部分(都大于双亲结点的值)所以如果最大值所在的结点有左子树的话,直接把其左子树接到其前驱结点(双亲结点)的右子结点;
具体代码:
BSTree* BSTreeDelete(BSTree* Root,int n) { BSTree *p=Root,*q,*s,*f=NULL; while(p){ if(p->x==n)break; f=p;//f为p的前驱 if(p->x>n)p=p->lchild; else p=p->rchild; } if(p==NULL)return Root;//找不到就返回 if(p->lchild==NULL){ //无左子树 if(f==NULL)Root=p->rchild;//未进入while循环,p为根节点 (因为要用到f为p前驱, 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!=NULL){ q=s; s=s->rchild; } if(q==p)p->lchild=s->lchild;//未进入while循环,s为p左子树,s无右子树.将s的左子树连到q上 else q->rchild=s->lchild; p->x=s->x; free(s); } return Root; }
相关文章推荐
- 9-7-平衡二叉排序(搜索)树-查找-第9章-《数据结构》课本源码-严蔚敏吴伟民版
- Linux下的搜索查找命令的详解(which)
- Linux 指令详解 find 查找搜索
- 二分查找/二分搜索(binary_search)详解
- Linux下的搜索查找命令的详解(find)
- Linux下的搜索查找命令的详解(whereis)
- Android Studio搜索功能(查找功能)及快捷键图文详解
- Linux下的搜索查找命令的详解(locate)
- Linux下动态共享库加载时的搜索路径详解
- [原创]让RichEdit支持中文搜索、向上查找、区分大小写!(花费一个多星期的成果)!
- VB6在ListBox或Combox中搜索字符串项的模块(支持模糊与精确查找)
- linux shell 字符串操作(长度,查找,替换)详解
- 文本查找查找命令的grep 、egrep、fgrep用法的详解
- python 二分查找和快速排序实例详解
- Linux文件查找小能手find使用详解
- 【数据结构】——搜索二叉树的插入,查找和删除(递归&非递归)
- pidof命令_Linux pidof 命令用法详解:查找指定名称的进程的进程号ID号
- Linux命令详解1--文件和目录管理之文件查找和比较
- 分布式搜索elasticsearch配置文件详解
- Android Studio查找功能(搜索功能)及快捷键