二叉搜索树是以一棵二叉树来组织的。在二叉树的基础上,增加了一些限制:
对于任何结点x,其左子树的任何结点都不大于x.key,右子树的任何结点都不小于x.key。
二叉树与二叉堆:
二者都是基于二叉树来构建的数据结构,但是二者的区别在于:
二叉堆(最大堆)的每个结点的值都大于等于其两个儿子的值,二叉查找树的父亲是小于等于其右孩子的。如下图:
基本操作:
(一)查找:Tree_search
输入参数:指向根结点的指针和要查找的关键字
返回值:如果存在该关键字,则返回关键字所在的结点。否则返回空
该过程从根结点开始查找,并沿着该树的一条路径向下进行。由于二叉搜索树要求每个结点是有序的,所以该过程十分类似二叉检索。
(二)最大最小关键字元素Tree_maximum、Tree_minimum
输入参数:二叉搜索树中的某一结点
返回值:以该指针为根的子树中的最大或最小结点
该过程也是利用了二叉搜索树的性质,可以快速地定位最大最小值。
(三)后继和前驱Tree_successor、Tree_predecessor
输入参数:二叉搜索树中的某一结点
返回值:该结点的前驱结点和后继结点
后继指比该元素大的下一个元素。如果是右子树非空,就返回右子树中的最左结点。否则就是该结点所有有左孩子的祖先结点中的最底层祖先。
前驱指比该元素小的下一个元素,其原理跟后继一样。
(四)插入Tree_insert
输入参数:要插入的结点、根结点
返回值:空
根据二叉搜索树的性质,找到该结点应放置的位置。可从根结点依次向下遍历,直到找到该元素适合的位置。
(五)删除Tree_delete
输入参数:要删除的结点、根结点
返回值:空
删除的结点需要分一下三种情况考虑:
①左子树、右子树都没有,即叶子结点:直接删除
②左子树、右子树二者有其一:将其子树直接连接在其父结点上
③左子树、右子树二者都有:首先删除其后继,并让后继的父结点成为后继的右子树的父结点,再将后继的值代替要删除结点的值
实现代码如下:
#include <iostream>
using namespace std;
struct Node
{
int key;
Node* right; //右孩子
Node* left; //左孩子
Node* parent; //父节点
};
Node tree_search( Node* x, int k )
{
if( x == NULL || k == x->key )
return x;
if( k < x->key )
return tree_search(x->left,k);
else
return tree_search(x->right,k);
}
Node tree_maximum( Node* x )
{
if( x->left == NULL )
return x;
else
return tree_maximum( x->left );
}
Node tree_minimum( Node* x )
{
if( x->right == NULL )
return x;
else
return tree_maximum( x->right );
}
Node tree_successor( Node* x )
{
if( x->right != NULL )
return tree_minimum(x->right);
Node* y = x->parent;
while( y!=NULL && x==y->right )
{
x = y;
y = y->parent;
}
return y;
}
void tree_insert( Node* z, Node* root )
{
Node* x = root;
Node* y = NULL;
while( x != NULL )
{
y = x;
if( z->key < x->key )
x = x->left;
else
x = x->right;
}
z->parent = y;
if( y == NULL )
root = z;
else if( z->key < y->key )
y->left = z;
else
y->right = z;
}
void Tree_delete( Node *z, Node* root )
{
Node* x,* y;
//若z最多只有一个孩子,就直接删除z
if( z->left == NULL && z->right == NULL )
y = z;
else
y = tree_successor( z );
//x表示实际要删除的结点的孩子
if( y->left != NULL )
x = y->left;
else
x = y->right;
//修改指针,删去结点
if( x != NULL )
x->parent = y->parent;
//实际要删除的结点是根结点
if( y->parent == NULL )
root = x;
else if( y == y->parent->left )
y->parent->left = x;
else
y->parent->right = x;
if( y != z )
{
z->key = y->key;
}
}