二叉搜索树Binary Search Tree(BSTs)又名二叉排序树,二叉查找树。而能够自平衡的叫平衡搜索树,包括AVL trees, 2-3 trees, 2-3-4 trees, B-trees, Red-Black Trees红黑树,skip lists跳跃表。

在二叉搜索树的基础上,又有最优二叉搜索树。

在此之前先说说三种遍历方式。

 中序遍历首先遍历左子树,然后访问根结点,最后遍历右子树。在遍历左、右子树时,仍然先遍历左子树,再访问根结点,最后遍历右子树。即:
若二叉树为空则结束返回
否则:
(1)中序遍历左子树。
(2)访问根结点。
(3)中序遍历右子树。

中序遍历
注意的是:遍历左右子树时仍然采用中序遍历方法。
如右图所示二叉树
中序遍历结果:DBEAFC
中序遍历的时间复杂度为:O(n)。
如果一棵二叉排序树的节点值是数值,中序遍历的结果为升序排列的数组。可以利用该性质检测一棵树是否为二叉排序数。
已知前序遍历和后序遍历,不能确定唯一的中序遍历。

void BinTree::preOrder(Node *r)//递归实现先序遍历
{  if(r==NULL)  {  return ;  }  else  {  cout<<r->data<<" ";  preOrder(r->left);  preOrder(r->right);  }
}
void BinTree::InOrder(Node *r)//递归实现中序遍历
{  if(r==NULL)  {  return ;  }  else  {  InOrder(r->left);  cout<<r->data<<" ";  InOrder(r->right);  }
}
void BinTree::PostOrder(Node *r)//递归实现后序遍历
{  if(r==NULL)  {  return ;  }  else  {  PostOrder(r->left);  PostOrder(r->right);  cout<<r->data<<" ";  }
}

一、二叉搜索树的定义

二叉搜索树或者是一棵空树,或者是具有下列性质的二叉树:

每个结点都有一个作为搜索依据的关键码(key),所有结点的关键码互不相同。

    左子树(如果非空)上 所有结点的关键码都小于根结点的关键码。
    右子树(如果非空)上所有结点的关键码都大于根结点的关键码。
    左子树和右子树也是二叉搜索树。(构建的二叉搜索树和输入节点的排序有关,排序不同,构造的二叉树也不同)
 
    如果对一棵二叉搜索树进行中序遍历,可以按从小到大的顺序,将各结点关键码排列起来,所以也称二叉搜索树为二叉排序树。

二、查询操作

在二叉搜索树中,查询操作时很核心的一个操作,在插入节点的时候,需要查看改节点是否已经存在,如果存在那么插入操作失败。并且在删除节点而不调整二叉树时,使用的策略和步骤是和查询操作一样的。

查询步骤如下:

    假设想要在二叉搜索树中搜索关键码为 x 的元素,搜索过程从根结点开始。
    如果 根指针(或者迭代的子树的根)为 NULL ,则 搜索不成功 ;并报告该空节点的父亲节点,即最后停留在的叶子节点。
    否则用给定值 x 与根结点的关键码进行比较:
         若 给定值等于根结点关键码 ,则 搜索成功 ,返回搜索成功; 并报告搜索到结点地址。
         若给定值小于根结点的关键码,则继续递归搜索根结点的左子树;
         否则。递归搜索根结点的右子树。
/********************************************************************
Method:      SearchBST
Description:
Access:      public
Returns:     int
Parameter:   T: the tree that will be searched, f:the father tree of thetree that will be searched       p:point to the elements that =key, or when result =0; point to the last leaf node
********************************************************************/
void SearchBST(BiTree T,int key,BiTree f,BiTree &p,int& result)
{result = 0;if(T == NULL){p=f;result = 0;}else if(key>T->data){SearchBST(T->rchild,key,T,p,result);}else if(key<T->data){SearchBST(T->lchild,key,T,p,result);}else if(key == T->data){p=T;result = 1;}
}

使用返回值的版本如下:

int SearchBST(BiTree T,int key,BiTree f,BiTree &p)
{int tmp1,tmp2;tmp1=tmp2=0;if(!T) {p=f;return 0;} //查找不成功else if(key==T->data) {p=T;return 1;} //查找成功else if(key<T->data) tmp1=SearchBST(T->lchild,key,T,p); //在左子树中继续查找else tmp2=SearchBST(T->rchild,key,T,p); //在右子树中继续查找if(tmp1||tmp2) return 1; //若在子树中查找成功,向上级返回1else return 0; //否则返回0*/
}

三、插入操作

每次结点的插入,都要先进行搜索操作,(搜索不成功;报告该空节点的父亲节点,最后停留在的叶子节点)。然后把新结点作为改叶结点的子节点插入。

int InsertBST(BiTree &T,int key)
{BiTree p,s;int result = 0;SearchBST(T,key,NULL,p,result);if(result == 0) //查找不成功,插入{s = new BiTNode;s->data=key;s->lchild=s->rchild=NULL;if(p == NULL) T=s; //被插结点*s为新的根结点else if(key<p->data) p->lchild=s; //被插结点*s为左孩子else p->rchild=s; //被插结点*s为右孩子return 1; //成功插入}else return 0; //树中已存在关键字为e的数据元素
}

四、删除操作

    在二叉搜索树中删除一个结点时,必须将因删除结点而断开的二叉链表重新链接起来,同时确保二叉搜索树的性质不会失去。
    为保证在删除后树的搜索性能不至于降低,还需要防止重新链接后树的高度增加。
    删除叶结点 ,只需将其双亲结点指向它的指针清零,再释放它即可。如a所示
    被删结点右子树为空 ,可以拿它的左子女结点顶替它的位置,再释放它。
    被删结点左子树为空 ,可以拿它的右子女结点 顶替它的位置,再释放它。如b所示
   被删结点左、右子树都不为空 ,可以在它的右子树中寻找中序下的第一个结点 ( 关键码最小 ), 用它的值填补到被删结点中,再来处理这个结点的删除问题。(这个点需要一个比他大的最少的数)

在B中,16的左子树空,16用他的右子树填补

在C中,5的左右子树都不为空,采取找到右子树最小值(中序查找到的第一个值),将6填入5,然后6变成了一个hole,递归执行直到最后一个取代的值的左右子树有一个为空,结束。原则是这样子,但是一般都不会使用递归实现。

取代的是,p是5,q从5开始,s是5的右子树,即q一直是s的前驱。然后s向左走到尽头,q一直保存前驱,最后s变为6,q为10, 然后将p上的值存储为6,将6的右子树接入到10的左子树

第一步,做类似查找的操作:

void DeleteBST(BiTree &T,int key, int& result)
{result = 0;if(T==NULL) {result = 0; //要搜索的子树为空}else{if(key==T->data)//找到关键字等于key的数据元素并删除它 {Delete(T); //在二叉排序树中删除结点p,并重接它的左或右子树result = 1;} else if(key<T->data) //继续在左子树中删除{DeleteBST(T->lchild,key,result);}else //继续在右子树中删除{DeleteBST(T->rchild,key,result); }}
}

第二步、实现Delete(T),删除节点p,重接它的 左右子树。

方法一:找到右子树最小的值。

方法二、找到左子树最大的值。

void Delete(BiTree &p)
{//在二叉排序树中删除结点p,并重接它的左或右子树BiTree s,q;if(p->rchild == NULL) //右子树空,只需重接它的左子树{cout<<"p value"<<p->data<<endl;q=p;p=p->lchild;free(q);}else if(p->lchild == NULL) //左子树空,只需重接它的右子树{cout<<"p2 value"<<p->data<<endl;q=p;p=p->rchild;free(q);}else //左右子树均不空{q=p;//q一直是s的前驱,负责保存s游走后的位置s=p->rchild;//s不断向左游走,转右,向左走到尽头while(s->lchild){q=s;s=s->lchild;} p->data=s->data; //q的值也被改变cout<<"s value"<<s->data<<endl;cout<<"q value"<<q->data<<endl;cout<<"p value"<<p->data<<endl;if(q!=p) q->lchild=s->rchild; else //删除78, 左右为65,94,q没有前进过地址没变,但是值变为了94{q->rchild=s->lchild; }free(s);}
}

整个可执行程序的代码如下:

演示的二叉堆为:

</pre><p></p><div style="top: 576px;"><pre name="code" class="cpp">#include <iostream>
using namespace std;
#define Maxsize 100
typedef struct BiTNode //定义二叉树节点结构
{int data; //结点的数据域struct BiTNode *lchild,*rchild; //左右孩子指针域
}BiTNode,*BiTree;
BiTNode *CreatBST(int A[],int n);
void SearchBST(BiTree,int,BiTree,BiTree&,int& result); //在二叉排序树中查找元素
int InsertBST(BiTree &,int); //在二叉排序树中插入元素
int DeleteBST(BiTree &,int); //在二叉排序树中删除元素
void Delete(BiTree &); //删除二叉排序树的根结点
void InorderBST(BiTree); //中序遍历二叉排序树,并显示
void inorder(BiTree T);
int A[Maxsize];BiTNode *CreatBST(int A[],int n)   //由数组A中的关键字建立一棵二叉排序树
{BiTNode *bt=NULL;                  //初始bt 为空树int i=0;while(i<n)if(InsertBST(bt,A[i])==1)      //将数组A[i]插入二叉排序树bt中{printf("  Step%d,Insert:%d:",i+1,A[i]);InorderBST(bt);printf("\n");i++;}return bt;                      //返回建立的二叉排序树的根指针
}void InorderBST(BiTree T)
{//以中序方式遍历二叉排序树T,并显示if(T!=NULL){printf("%d",T->data);if(T->lchild!=NULL||T->rchild!=NULL){printf("(");InorderBST(T->lchild);//递归调用中序遍历函数if(T->rchild!=NULL)printf(",");InorderBST(T->rchild); //递归调用中序遍历函数printf(")");}}}
void inorder(BiTree T)
{if(T!=NULL){inorder(T->lchild);cout<<" "<<T->data;inorder(T->rchild);}
}/********************************************************************
Method:      SearchBST
Description:
Access:      public
Returns:     int
Parameter:   T: the tree that will be searched, f:the father tree of thetree that will be searched       p:point to the elements that =key, or when result =0; point to the last leaf node
********************************************************************/
void SearchBST(BiTree T,int key,BiTree f,BiTree &p,int& result)
{result = 0;if(T == NULL){p=f;result = 0;}else if(key>T->data){SearchBST(T->rchild,key,T,p,result);}else if(key<T->data){SearchBST(T->lchild,key,T,p,result);}else if(key == T->data){p=T;result = 1;}
}int InsertBST(BiTree &T,int key)
{BiTree p,s;int result = 0;SearchBST(T,key,NULL,p,result);if(result == 0) //查找不成功,插入{s = new BiTNode;s->data=key;s->lchild=s->rchild=NULL;if(p == NULL) T=s; //被插结点*s为新的根结点else if(key<p->data) p->lchild=s; //被插结点*s为左孩子else p->rchild=s; //被插结点*s为右孩子return 1; //成功插入}else return 0; //树中已存在关键字为e的数据元素
}int DeleteBST(BiTree &T,int key)
{//若二叉排序树T中存在关键字等于key的数据元素时,则删除该数据元素结点
//并返回1,否则返回0int tmp1,tmp2;tmp1=tmp2=0;if(!T) return 0; //不存在关键字等于key的数据元素else{if(key==T->data)   {Delete(T); return 1;} //找到关键字等于key的数据元素并删除它else if(key<T->data) tmp1=DeleteBST(T->lchild,key); //继续在左子树中删除else tmp2=DeleteBST(T->rchild,key); //继续在右子树中删除if(tmp1||tmp2) return 1; //在子树中删除成功,返回1else return 0; //不存在该元素,返回0}
}void Delete(BiTree &p)
{//在二叉排序树中删除结点p,并重接它的左或右子树BiTree s,q;if(p->rchild == NULL) //右子树空,只需重接它的左子树{cout<<"p value"<<p->data<<endl;q=p;p=p->lchild;free(q);}else if(p->lchild == NULL) //左子树空,只需重接它的右子树{cout<<"p2 value"<<p->data<<endl;q=p;p=p->rchild;free(q);}else //左右子树均不空{q=p;//q一直是s的前驱,负责保存s游走后的位置s=p->rchild;//s不断向左游走,转右,向左走到尽头while(s->lchild){q=s;s=s->lchild;} p->data=s->data; //q的值也被改变cout<<"s value"<<s->data<<endl;cout<<"q value"<<q->data<<endl;cout<<"p value"<<p->data<<endl;if(q!=p) q->lchild=s->rchild; else //删除78, 左右为65,94,q没有前进过地址没变,但是值变为了94{q->rchild=s->lchild; }free(s);}
}void main()
{BiTree T,p;int ch,keyword;char j='y';//控制程序结束与否int temp; printf("Creat the BST!\n");const int n = 10;int A[n]={53,17,78,9,45,65,94,23,81,88};T=CreatBST(A,n);//调用建树函数建树inorder(T);while(j!='n'){printf("1.display\n");printf("2.search\n");printf("3.insert\n");printf("4.delete\n");printf("5.exit\n");scanf(" %d",&ch); //输入操作选项switch(ch){ case 1:if(!T) printf("The BST has no elem.\n");else {InorderBST(T);printf("\n");}//中序遍历并显示break;case 2:printf("Input the keyword of elem to be searched(a number):");scanf(" %d",&keyword); //输入要查找元素的关键字SearchBST(T,keyword,NULL,p,temp);//查找if(!temp) printf("%d isn't existed!\n",keyword); //没有找到else printf("%d has been found!\n",keyword); //成功找到break;case 3:printf("Input the keyword of elem to be inserted(a number):");scanf(" %d",&keyword); //输入要插入元素的关键字temp=InsertBST(T,keyword);//插入if(!temp) printf("%d has been existed!\n",keyword); //该元素已经存在else printf("Sucess to inert %d!\n",keyword); //成功插入break;case 4:printf("Input the keyword of elem to be deleted(a number):");scanf(" %d",&keyword); //输入要删除元素的关键字temp=DeleteBST(T,keyword);//删除InorderBST(T);if(!temp) printf("%d isn't existed!\n",keyword); //该元素不存在else printf("Sucess to delete %d\n",keyword); //成功删除break;case 5: j='n';//跳出循环,结束程序}}printf("The program is over!\nPress any key to shut off the window!\n");getchar();getchar();
}

二叉搜索树--基础篇相关推荐

  1. 高度平衡的二叉搜索树基础概念与经典题目(Leetcode题解-Python语言)

    高度平衡的二叉搜索树(平衡二叉树),定义见此Leetbook.简单来说,就是基于相同节点值构建出来的二叉搜索树中高度最小的,即为平衡二叉树(不唯一).有 N 个节点的平衡二叉搜索树,它的高度是 log ...

  2. 九章基础算法04:二叉搜索树与哈希表

    目录 1. 什么是二叉搜索树 1.1 二叉搜索树结构 1.2 二叉搜索树特性应用 2. 二叉搜索树基础实现 2.1 BST类型与构造函数 2.2 插入操作 2.2.1 思路分析 2.2.2 递归实现 ...

  3. 数据结构 --- c语言二叉搜索树(有序的树)

    二叉搜索树基础 左边的孩子节点 < 父节点的值,右边孩子节点 > 父节点的值 每棵二叉搜索树的子树也是一棵二叉搜索树 10 充当根节点 18 > 根节点,应该放在根节点的右边:3 & ...

  4. 二叉搜索树BST红黑树

    二叉搜索树基础知识 提起红黑树咱们肯定要先说说这个二叉搜索树(BST) 二叉搜索树又叫二叉查找树,二叉排序树:它具有以下特点: 如果它的左子树不为空,则左子树上结点的值都小于根结点. 如果它的右子树不 ...

  5. 二叉搜索树(创建,插入,删除):基础篇,适合新手观看。

    1.1 二叉搜索树的插入 二叉搜索树的概念相信大家都很清楚,无非就是左小右大 创建二叉搜索树,其实就是多次调用二叉搜索树的插入方法,所以首先我们来讲讲如何插入节点到二叉搜索树里,假设一颗二叉搜索树如下 ...

  6. 算法基础知识科普:8大搜索算法之二叉搜索树(下)

    由于微信发代码以及数学符号很吃力,所以我们做知识科普只能利用图片来做,本算法代码较多,所以分为三个部分来介绍.本篇把剩余的部分补齐.当然二叉搜索树也有自己的缺陷,即构造的二叉树跟数据的初始状态以及删除 ...

  7. 算法基础知识科普:8大搜索算法之二叉搜索树(中)

    昨天图文介绍了二叉搜索树的基本概念,本篇图文介绍二叉搜索树的具体实现.既然二叉搜索树是二叉树的特殊应用,所以我们首先封装二叉树的结点,即数据-左子树-右子树,然后实现ISymbolTalbe接口中的方 ...

  8. 【基础知识】 之 Binary Search Tree 二叉搜索树

    前言 这个系列是毕业找工作的复习笔记,希望可以和广大正准备毕业的童鞋一起打牢基础,迎接各种笔试--为了应付中英文笔试,关键词都用英文进行标注,这样就不怕面对英文题目了.之所以开始这一系列是因为之前在参 ...

  9. 【力扣动态规划基础专题】:509. 斐波那契数 70. 爬楼梯 746. 使用最小花费爬楼梯 62. 不同路径 63. 不同路径 II 343. 整数拆分 96. 不同的二叉搜索树

    /** 动态规划专题:这是最简单的并且已经给出了转移方程,平时我们用dp[]数组来表示转移方程转移方程: dp[n] = dp[n-1]+dp[n-2]初始值:dp[0] = 0 , dp[1] = ...

最新文章

  1. 太智能了!国内首批自动驾驶出租车即将在长沙上路!
  2. c# 获取excel单元格公式结果_excel公式应用技巧:文字和数字混合的单元格,如何求和?...
  3. linux上传文件到服务器
  4. chrome 不支持12px以下字体为题的解决
  5. Common Techniques to Improve Shadow Depth Maps
  6. Java即时编译器JIT之简单介绍
  7. python中的time的时间戳_python中time、date、时间戳的转换
  8. 2013Esri全球用户大会之ArcGIS for ServerPortal for ArcGIS
  9. python中静态方法、类方法、属性方法区别
  10. 锐捷Linux版的下载和使用(福大客户端)
  11. mescroll-vue下拉上拉刷新的使用
  12. Reno与RACK对丢失/重传报文的标记
  13. Airbnb产品运营分析报告
  14. GitHub---团队合作
  15. SpringBoot集成文件 - 如何基于POI-tl和word模板导出庞大的Word文件?
  16. WGS84(GPS)、火星坐标系(GCJ02)、百度地图(BD09)坐标系转换案例教程(附转换工具下载)
  17. 算法分析——Hanoi塔问题
  18. Windows11之Dev-C++超详细下载安装与使用教程
  19. amazon - sellercentral 之 sellercentral report - long term storage fee report
  20. c语言编写一个程序计算某年某月有几天,c语言编写程序,输入某年某月,求该月的天数...

热门文章

  1. Serial Nor Flash
  2. ups如何保护计算机,UPS电源保护计算机的三种配置方案
  3. mybatis+oracle存储大文本类型
  4. 仿作苏宁易购主页(前端学习记录)
  5. 篮球杯2021年省赛
  6. C# Textbox屏蔽中文输入法
  7. Android LCM特殊分辨率时,360camera预览异常分析
  8. Jackson工具类
  9. 建造自己的「天空之城」,密歇根大学博士后的这项研究可以虚空造物、偷天换日...
  10. Ag (the_silver_searcher) 安装使用