简介
搜索树是一种可以进行插入,搜索,删除等操作的数据结构,可以用作字典或优先级队列。二叉搜索树是最简单的搜索树。其左子树的键值<=根节点的键值,右子树的键值>=根节点的键值。
如果共有n个元素,那么每次操作需要的O(log n)的时间.
常用知识点
- 满二叉树 : 一棵深度为k,且有2^k-1个节点的二叉树,称为满二叉树。这种树的特点是每一层上的节点数都是最大节点数。
- 完全二叉树 : 而在一棵二叉树中,除最后一层外,若其余层都是满的,并且最后一层要么是满的,要么在右边缺少连续若干节点,则此二叉树为完全二叉树。具有n个节点的完全二叉树的深度为floor(log2n)+1。深度为k的完全二叉树,至少有2^(k-1)个叶子节点,至多有2^k-1个节点。
基本操作
- 查找(search)
- 插入(insert)
- 删除(remove)
操作原理
查找
假设查找的值为x,从根节点的值开始比对,如果小于根节点的值,则往左儿子继续查找,如果大于根节点的值,则往右儿子继续查找.依次类推.直到当前节点的值等于要查找的值.

插入
按照查找的步骤即可找到插入值应该在的位置.

删除
删除操作实现起来最为麻烦,因为删除某个节点后, 如果它有子孙,还有将它的子孙接到原树上. 而它的子孙可能出现的情况较多, 可以分为一下三类.
1. 需要删除的节点没有左儿子, 则把右儿子接到二叉树上. 如下图,若删除值为5的节点,只需要将值为7的节点接到原先5的节点即可
2. 需要删除的节点的左儿子没有右儿子, 那么把左儿子接到二叉树上. 如下图, 若删除值为5的节点, 只需将值为3的节点接到原先5的位置即可.
3. 以上两种情况都不满足, 就把左儿子的子孙中最大的节点, 即右子树的右子树的...右子树, 提到需要删除的节点位置. 如下图, 若删除值位5的节点, 先找到其子孙中值最大的节点, 即值为9的节点, 然后将该节点提到5的位置.
代码实现
//BST节点
struct node{
// 值
int val;
// 指向左右子树的指针
node *lch,*rch;
};
// 插入数值x
node *insert(node *p,int x){
if(p==NULL){
// 如果p为空指针,则申请一个节点的空间并将左右子树设为空,返回该节点
node *q = new node;
q->val = x;
q->lch = q->rch = NULL;
return q;
}else{
// 如果p不为空,将x与p的值进行比较, 如果x小于val,则将x插入左子树,否则插入右子树
if(x<p->val) p->lch=insert(p->lch,x);
else p->rch = insert(p->rch,x);
return p;
}
}
// 查找数值x,p为根节点
bool find(node *p,int x){
if(p==NULL) return false;
else if(x==p->val) return true;
else if(x<p->lch) return find(p->lch,x);
else return find(p->rch,x);
}
// 删除数值x
node *remove(node *p,int x){
if(p==NULL) return NULL;
// 找到要删除的节点
else if(x<p->val) p->lch=remove(p->lch,x);
else if(x>p->val) p->rch=remove(p->rch,x);
// 如果要删除的节点没有左儿子,那么就把右儿子提上去
else if(p->lch==NULL){
node *q=p->rch;
delete p;
return q;
// 如果要删除的节点的左儿子没有右儿子,就把左儿子提上去
}else if(p->lch->rch==NULL){
node *q = p->lch;
q->rch = p->rch;
delete p;
return q;
// 如果以上情况都不满足,就把左儿子的子孙中最大的节点(右儿子的右儿子的。。。右儿子)提到需要删除的节点上
}else{
node *q;
// 用for循环进行遍历,这一招妙啊
for(q=p->lch;q->rch->rch!=NULL;q=q->rch);
node *r=q->rch;
q->rch = r->lch;
r->lch=p->lch;
r->rch=p->rch;
delete p;
return r;
}
return p;
}
代码测试
#include<iostream>
#include "BST.h"
using namespace std;
int main(){
// 声明一个指向根节点的指针
node *root=NULL;
// 判断二叉树是否为空
if(root==NULL) cout<<"empty"<<endl;
// 插入数值
root = insert(root,1);
// 查找数值
if(find(root,1)) cout<<1<<endl;
// 删除数值
root=remove(root,1);
// 再次判空
if(root==NULL) cout<<"empty"<<endl;
return 0;
}
运行结果
本文参考了<<挑战程序设计竞赛>>一书的P77-81, 部分图片截取自书上.