前沿:
首先让我们认识下什么是二叉搜索树,二叉搜索树是十分高效的一种搜索算法,定义为:它的每个节点都有以下性质(在左右子树都不为空的情况下)自己本身的权值比它的左子树大,自己本身的权值比它的右子树小。简单的说比它小的在左边,比它大的在右边。如下图所示:
![这里写图片描述](http://r.photo.store.qq.com/psb?/V110esId09m16E/oCHGZPKANUlMMsHsdm6zoEsFN7B5qPY2TXpaIiLoWLs!/o/dHMBAAAAAAAA&ek=1&kp=1&pt=0&bo=cgSAAoAEiAIDAN8!&su=128397201&tm=1500602400&sce=0-12-12&rf=2-9)
相信聪明的你已经猜到规则了。
主要操作:
插入
第 一,就是插入了,其实初始化就是通过插入实现的,都一样。
自己在纸上画画就会发现其实插入的位置肯定是某个叶子节点的位置,这样就很好理解了,首先从根节点开始找,要是比此节点小就搜节点的左子树,比节点大就搜节点的右子树,直到搜到某个节点为空(就是某个叶子节点),再将这个节点赋值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了。
![这里写图片描述](http://r.photo.store.qq.com/psb?/V110esId09m16E/vI1FnJfCjdRbfhlo8pBtTNubVkulCnSeQYHQ31jkyzU!/o/dIcBAAAAAAAA&ek=1&kp=1&pt=0&bo=cgSAAoAEiAIDAN8!&su=127727969&tm=1500602400&sce=0-12-12&rf=2-9)
情况三:这个情况比较难,我就难于用文字描述了,简单的说先要将T右子树最小值去覆盖T的值,再转变为删除这个最小值的操作,为什么要找T右子树的最小值?因为根据二叉搜索树的性质:节点T左边的子树所有节点都小于节点T,节点右边的子树都大于节点T,所以要删除两个孩子的节点就要找节点T右子树最小的节点值代替它,这样就能保持二叉搜索树的性质。
![这里写图片描述](https://img-blog.csdn.net/20170721114958884?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMjQwMjg3NTM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
代码范式:
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);
}
}
代码实现
下面就贴代码吧:
二叉搜索树链式:
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;
}
![这里写图片描述](https://img-blog.csdn.net/20170721111854359?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMjQwMjg3NTM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
二叉搜索树数组式:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAX=10000;
const int NIL=-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;
}
return 0;
}
![这里写图片描述](https://img-blog.csdn.net/20170721112018508?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMjQwMjg3NTM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
二叉搜索树的缺点
在一般情况下二叉搜索树的插入,搜索,删除时间复杂度是O(logn),但是如果插入的数都是递增的话 如:(1,2,3,4,5,6,7,…)
如图所示:
![这里写图片描述](https://img-blog.csdn.net/20170721112624086?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMjQwMjg3NTM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
这时插入,搜索,删除时间复杂度是O(n)
那么怎么解决这个问题呢:这问题的主要原因是数据偏向单边,使树的高度线性增长,为了能做到插入的数据不偏向单边,如果个节点的左子树高度与右子树高度相差<=1,那么就能做到插入,搜索,删除时间复杂度是O(logn),于是就有了平衡的概念,二叉平衡搜索树(AVL树)就出来了,这里的主题就不讲二叉平衡搜索树(AVL树)了,到时专门写一个二叉平衡搜索树的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)