二叉搜索树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),所有结点的关键码互不相同。
在二叉搜索树中,查询操作时很核心的一个操作,在插入节点的时候,需要查看改节点是否已经存在,如果存在那么插入操作失败。并且在删除节点而不调整二叉树时,使用的策略和步骤是和查询操作一样的。
查询步骤如下:
/******************************************************************** Method: SearchBST Description: Access: public Returns: int Parameter: T: the tree that will be searched, f:the father tree of the tree 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; //若在子树中查找成功,向上级返回1 else 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的数据元素 }
在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); } } }
方法一:找到右子树最小的值。
方法二、找到左子树最大的值。
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 the tree 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,否则返回0 int 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; //在子树中删除成功,返回1 else 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(); }