二叉查找树(英语:Binary Search Tree),也称二叉搜索树、有序二叉树(英语:ordered binary tree),排序二叉树(英语:sorted binary tree),是指一棵空树或者具有下列性质的二叉树:
- 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
- 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
- 任意节点的左、右子树也分别为二叉查找树;
- 没有键值相等的节点。
从上述定义可知,二叉排序树是记录之间满足一定次序关系的二叉树。下面介绍如何构建一棵二叉排序树,以及遍历,插入,查找,也会简单的介绍删除结点操作。
构造一棵排序二叉树,则一定要根据其定义来实现。下面给出相关代码:
#include<iostream>
using namespace std;
typedef struct bstNote {
int data;
struct bstNote *lchild, *rchild;
}*bstTree;
void insertNote(bstTree &bst, int _data) {
if (bst == NULL) {
bst = new bstNote;
bst->data = _data;
bst->lchild = bst->rchild = NULL;
return;
}
if (bst->data == _data) {
exit(-1);
}
else if(bst->data > _data)
insertNote(bst->lchild, _data);
else
insertNote(bst->rchild, _data);
}
void createBST(bstTree &bst,int *arry,int length){
bst = NULL;
for (int i = 0; i < length; i++) {
insertNote(bst, arry[i]);
}
}
void preOrder(bstTree bst) {
if (bst == NULL) {
return;
}
cout << bst->data << " ";
preOrder(bst->lchild);
preOrder(bst->rchild);
}
void inOrder(bstTree bst) {
if (bst == NULL) {
return;
}
inOrder(bst->lchild);
cout << bst->data << " ";
inOrder(bst->rchild);
}
void postOrder(bstTree bst) {
if (bst == NULL) {
return;
}
postOrder(bst->lchild);
postOrder(bst->rchild);
cout << bst->data << " ";
}
bstTree searchBST(bstTree bst, int key) {
if (bst == NULL)
return false;
else if (bst->data == key) {
cout << "查找成功:"<<bst->data<< endl;
return bst;
}
else if(bst->data>key)
return searchBST(bst->lchild, key);
else
return searchBST(bst->rchild, key);
}
int main(){
bstTree bst;
int arry[] = {4,5,2,1,3,10,7,8,6,0};
int length = sizeof(arry) / sizeof(int);
createBST(bst, arry, length);
cout << "PreOrder:" << endl;;
preOrder(bst);
cout << endl;
cout << "InOrder:" << endl;
inOrder(bst);
cout << endl;
cout << "PostOrder:" << endl;;
postOrder(bst);
cout << endl;
searchBST(bst,6);
insertNote(bst, 9);
preOrder(bst);
cout << endl;
inOrder(bst);
}
上面的代码比较简单的实现构造,遍历,查找。
但是在二叉查找树删去一个结点,分三种情况讨论:(如下参考维基百科: 点击打开链接 )
1. 若*p结点为叶子结点,即PL(左子树)和PR(右子树)均为空树。由于删去叶子结点不破坏整棵树的结构,则只需修改其双亲结点的指针即可。
2. 若*p结点只有左子树PL或右子树PR,此时只要令PL或PR直接成为其双亲结点*f的左子树(当*p是左子树)或右子树(当*p是右子树)即可,作此修改也不破坏二叉查找树的特性。
3.若*p结点的左子树和右子树均不空。在删去*p之后,为保持其它元素之间的相对位置不变,可按中序遍历保持有序进行调整,可以有两种做法:其一是令*p的左子树为*f的左/右(依*p是*f的左子树还是右子树而定)子树,*s为*p左子树的最右下的结点,而*p的右子树为*s的右子树;其二是令*p的直接前驱(in-order predecessor)或直接后继(in-order successor)替代*p,然后再从二叉查找树中删去它的直接前驱(或直接后继),该种情况较为复杂,如下图示。
算法:
Status DeleteBST(BiTree &T, KeyType key){
//若二叉查找树T中存在关键字等于key的数据元素时,则删除该数据元素,并返回
//TRUE;否则返回FALSE
if(!T)
return false; //不存在关键字等于key的数据元素
else{
if(key == T->data.key) { // 找到关键字等于key的数据元素
return Delete(T);
}
else if(key < T->data.key)
return DeleteBST(T->lchild, key);
else
return DeleteBST(T->rchild, key);
}
}
Status Delete(BiTree &p){
//该节点为叶子节点,直接删除
BiTree *q, *s;
if (!p->rchild && !p->lchild)
{
delete p;
p = NULL;
}
else if(!p->rchild){ //右子树空则只需重接它的左子树
q=p->lchild;
p->data = p->lchild->data;
p->lchild=p->lchild->lchild;
p->rchild=p->lchild->rchild;
delete q;
}
else if(!p->lchild){ //左子树空只需重接它的右子树
q=p->rchild;
p->data = p->rchild->data;
p->lchild=p->rchild->lchild;
p->rchild=p->rchild->rchild;
delete q; }
else{ //左右子树均不空
q=p;
s=p->lchild;
while(s->rchild){
q=s;
s=s->rchild;
} //转左,然后向右到尽头
p->data = s->data; //s指向被删结点的“前驱”
if(q!=p)
q->rchild = s->lchild; //重接*q的右子树
else
q->lchild = s->lchild; //重接*q的左子树
delete s;
}
return true;
}