二叉搜索树详解链式与数组式实现
来源:互联网 发布:投资软件靠谱吗 编辑:程序博客网 时间:2024/05/19 11:46
前沿:
首先让我们认识下什么是二叉搜索树,二叉搜索树是十分高效的一种搜索算法,定义为:它的每个节点都有以下性质(在左右子树都不为空的情况下)自己本身的权值比它的左子树大,自己本身的权值比它的右子树小。简单的说比它小的在左边,比它大的在右边。如下图所示:
相信聪明的你已经猜到规则了。
主要操作:
插入
第 一,就是插入了,其实初始化就是通过插入实现的,都一样。
自己在纸上画画就会发现其实插入的位置肯定是某个叶子节点的位置,这样就很好理解了,首先从根节点开始找,要是比此节点小就搜节点的左子树,比节点大就搜节点的右子树,直到搜到某个节点为空(就是某个叶子节点),再将这个节点赋值key,就OK了。
现在让我们画画图吧:
代码范式:
void insert(node **T,int n)//插入{ if((*T)==NULL) { (*T)=new(node); (*T)->lchild=NULL; (*T)->rchild=NULL; (*T)->key=n; return ; } if((*T)->key>n) insert(&((*T)->lchild),n); else insert(&((*T)->rchild),n);}
搜索
第二,就是搜索操作了
搜索跟插入是类似的,首先从根节点开始找,要是比此节点小就搜节点的左子树,比节点大就搜节点的右子树,直到搜到某个节点为空还没找到就是不存在咯,否则就是存在。
node * search(node *T,int n)//搜索{ if(T==NULL||T->key==n) { return T; } if(T->key>n) {cout<<'W';search(T->lchild,n);} else {cout<<'E';search(T->rchild,n);}}
删除
第三,就是删除操作了
这是这里最难的一个了,因为得考虑三个方面:
1)当要删除的节点没有左右孩子;;
2)当要删除的节点只有一个左右孩子;
3)当要删除的节点有两个左右孩子;
情况一:最简单了,因为这节点肯定是叶子节点,直接将这个节点置空,再直接free()这个节点,就OK了。
情况二: 只要改变要删除的节点T的父节点的孩子就好了,只要将T的孩子替换T,再free()T节点就OK了。
情况三:这个情况比较难,我就难于用文字描述了,简单的说先要将T右子树最小值去覆盖T的值,再转变为删除这个最小值的操作,为什么要找T右子树的最小值?因为根据二叉搜索树的性质:节点T左边的子树所有节点都小于节点T,节点右边的子树都大于节点T,所以要删除两个孩子的节点就要找节点T右子树最小的节点值代替它,这样就能保持二叉搜索树的性质。
代码范式:
node *minimum(node *t)//最小结点{ if(t->lchild!=NULL) return minimum(t->lchild); return t;}void Delete(node **T,int x)//删除结点{ if((*T)->key>x) Delete(&((*T)->lchild),x); else if((*T)->key<x) Delete(&((*T)->rchild),x); else if((*T)->lchild&&(*T)->rchild)//两个节点情况 { node *p=minimum((*T)->rchild); (*T)->key=p->key; Delete(&((*T)->rchild),(*T)->key); } else //叶子节点或有一个叶子节点情况 { node *p=(*T); if((*T)->lchild==NULL) (*T)=(*T)->rchild; else if((*T)->rchild==NULL) (*T)=(*T)->lchild; free(p); }}
代码实现
下面就贴代码吧:
二叉搜索树链式:
#include <iostream>#include <cstdio>#include <cstdlib>using namespace std;//二叉搜索树typedef struct node{ int key; struct node *lchild; struct node *rchild;} node;void creat(node **T)//初始化{ *T=NULL;}void insert(node **T,int n)//插入{ if((*T)==NULL) { (*T)=new(node); (*T)->lchild=NULL; (*T)->rchild=NULL; (*T)->key=n; return ; } if((*T)->key>n) insert(&((*T)->lchild),n); else insert(&((*T)->rchild),n);}void inordor (node *T)//中序遍历{ if(T!=NULL) { inordor(T->lchild); printf("%-3d",T->key); inordor(T->rchild); }}node * search(node *T,int n)//搜索{ if(T==NULL||T->key==n) { return T; } if(T->key>n) {cout<<'W';search(T->lchild,n);} else {cout<<'E';search(T->rchild,n);}}node *minimum(node *t)//最小结点{ if(t->lchild!=NULL) return minimum(t->lchild); return t;}node *maxmum(node *t)//最大结点{ if(t->rchild!=NULL) return maxmum(t->rchild);}void Delete(node **T,int x)//删除结点{ if((*T)->key>x) Delete(&((*T)->lchild),x); else if((*T)->key<x) Delete(&((*T)->rchild),x); else if((*T)->lchild&&(*T)->rchild) { node *p=minimum((*T)->rchild); (*T)->key=p->key; Delete(&((*T)->rchild),(*T)->key); } else { node *p=(*T); if((*T)->lchild==NULL) (*T)=(*T)->rchild; else if((*T)->rchild==NULL) (*T)=(*T)->lchild; free(p); }}int main(){ int n; node *T; creat(&T); printf("初始化二叉搜索树个数:"); scanf("%d",&n); for(int i=0; i<n; ++i) { int a; scanf("%d",&a); insert(&T,a); } int m; inordor(T); printf("\n"); scanf("%d",&m); // if(search(T,m)==NULL) // printf("NO\n"); // printf("\n"); Delete(&T,m); //node *p=minimum(T); // printf("%d\n",p->key); inordor(T); free(T); return 0;}
二叉搜索树数组式:
#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int MAX=10000;const int NIL=-1;//定义-1为空int tree[MAX];void Insert(int root,int x)//插入操作{ if(tree[root]==NIL) { tree[root]=x; return ; } if(tree[root]>=x) Insert(root*2,x); else Insert(root*2+1,x);}bool Search(int root,int x){ while(tree[root]!=NIL) { if(tree[root]==x) return true; if(tree[root]>x) root*=2; else root=root*2+1; } return false;}void bianli(int root)//中序遍历{ if(tree[root]==NIL) return ; else { bianli(root*2); printf("%-3d",tree[root]); bianli(root*2+1); }}int TRmin(int root)//返回最小值{ if(tree[root*2]==NIL) return tree[root]; return TRmin(root*2);}void Delete(int root,int x){ if(tree[root]>x) Delete(root*2,x); else if(tree[root]<x) Delete(root*2+1,x); else if(tree[root*2]!=NIL&&tree[root*2+1]!=NIL) { int key=TRmin(root*2+1); tree[root]=key; Delete(root*2+1,key); } else if(tree[root*2]==NIL&&tree[root*2+1]==NIL) { tree[root]=-1; } else { if(tree[root*2]==NIL) { tree[root]=tree[root*2+1]; Delete(root*2+1,tree[root*2+1]); } else { tree[root]=tree[root*2]; Delete(root*2,tree[root*2]); } }}int main(){ int n; printf("初始化节点数n:"); while(scanf("%d",&n)!=EOF) { int a; memset(tree,-1,sizeof(tree)); printf("输入数据:"); for(int i=0;i<n;++i) { scanf("%d",&a); Insert(1,a); } printf("中序遍历结果为:"); bianli(1); cout<<endl; if(Search(1,9)) cout<<"Yes"<<endl; else cout<<"No"<<endl;// while(1)// {// int b;// scanf("%d",&b);// Delete(1,b);// bianli(1);// } // printf("%d\n",TRmin(1)); } return 0;}
二叉搜索树的缺点
在一般情况下二叉搜索树的插入,搜索,删除时间复杂度是O(logn),但是如果插入的数都是递增的话 如:(1,2,3,4,5,6,7,…)
如图所示:
这时插入,搜索,删除时间复杂度是O(n)
那么怎么解决这个问题呢:这问题的主要原因是数据偏向单边,使树的高度线性增长,为了能做到插入的数据不偏向单边,如果个节点的左子树高度与右子树高度相差<=1,那么就能做到插入,搜索,删除时间复杂度是O(logn),于是就有了平衡的概念,二叉平衡搜索树(AVL树)就出来了,这里的主题就不讲二叉平衡搜索树(AVL树)了,到时专门写一个二叉平衡搜索树的。
- 二叉搜索树详解链式与数组式实现
- 二叉搜索树-链式结构实现方式
- 用链式结构实现二叉搜索树
- 链式Tree->二叉搜索树
- 使用动态分配的链式结构实现的二叉搜索树
- 二叉搜索树算法详解与Java实现
- 静态数组实现的二叉搜索树
- 二叉搜索树的数组实现
- 二叉搜索树-数组的实现方式
- 链式结构实现二叉树
- 二叉树链式结构实现
- 二叉树-链式-递归实现
- 二叉树操作链式实现
- 链式二叉树的实现
- 二叉树的链式实现
- 二叉树的链式存储与实现(C++)
- 二叉搜索树实现与测试
- 二叉搜索树的性质与实现
- Kali Linux进行内网攻击--》使用arpspoof
- java基于StringBuilder自己实现myArrayList
- 对SSH(Struct、Spring、Hibernate)框架的理解
- Java后台之路(19)-MyBatis之xml配置
- VINS ---初始化
- 二叉搜索树详解链式与数组式实现
- nyoj-58 最少步数
- JSTL核心标签库中的用法
- 转载-Android运行时异常“Binary XML file line # : Error inflating class”
- Kubernetes 核心原理 之一
- <machine learning traning> KNN
- java list对元素进行指定多个字段属性按多种排序方式进行排序
- C++ 调用打印机 打印一段文字
- 不错的递归题:输入123,返回“321”。 要求必须用递归,不能用全局变量,输入必须是一个参数,必须返回字符串。