二叉搜索树是以一棵二叉树来组织的。在二叉树的基础上,增加了一些限制:
对于任何结点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;
- }
- }