目录
二叉搜索树(binnary search tree)
一.二叉搜索树的定义和性质
一颗二叉搜索树是按照二叉树结构来组织的,这样的树可以用链表来表示,其中每一个结点都是一个对象。结点中除了key域和其他数据外,还有域left,right和fa,它们分别指向结点的左儿子,右儿子和父结点。如果某个儿子结点或父结点不存在,则相应域中的值即为NULL。根结点是树中唯一的父结点域为NULL的结点。
1.设x为二叉搜索树中的一个结点,如果y是x的左子树上的一个结点,则key[y]<=key[x]; 如果y是x的右子树中的一个结点,则key[y]>=key[x].
2.二叉搜索树可支持查找结点,查找树最大值和最小值,查找树结点前驱和后继,插入新的树结点,删除树结点等动态集合操作,这些基本操作的时间复杂度为O(h),h为二叉搜索树的高度.
3.中序遍历输出一颗二叉搜索树的时间复杂度为O(n),n为树结点的个数
二.二叉搜索树的结构
struct BST_Node{ //树结点
int key;
BST_Node *fa, *left, *right;
};
struct BST_tree{ //二叉搜索树(binnary search tree)
BST_Node *root; //二叉搜索树的根结点
void BST_inorder(BST_Node *x); //中序遍历输出一颗二叉搜索树
void BST_printf(BST_Node *x, int n); //逆时90度输出一颗二叉搜索树
BST_Node* BST_search(BST_Node *x,int k); //查找key值为k的树结点
BST_Node* BST_minnum(BST_Node* x); //查找以x为根结点的树的最小值
BST_Node* BST_maxnum(BST_Node* x); //查找以x为根结点的树的最大值
BST_Node* BST_successor(BST_Node* x); //查找x的后继结点
BST_Node* BST_precursor(BST_Node* x); //查找x的前驱结点
void BST_insert(BST_Node* x); //插入新的树结点
BST_Node* BST_delete(BST_Node* x); //删除树结点
}T;
三.输出一颗二叉搜索树
1.可以用中序遍历的方式按照排序顺序输出树中的关键字,设x是树结点的某一点,则中序遍历是先输出x的左子树,再输出x结点的值,然后再输出x的右子树
2.有时候按照顺序排序输出一颗二叉树并不能非常直观的看出树的结点之间的关系,可以用稍微修改后的中序遍历方法,逆时针90度输出一颗二叉树。
void BST_tree::BST_inorder(BST_Node *x){ //中序遍历输出一颗二叉搜索树
if (x != NULL){
BST_inorder(x->left);
printf("%d ", x->key);
BST_inorder(x->right);
}
}
void BST_tree::BST_printf(BST_Node *x, int n){ //逆时90度输出一颗二叉搜索树
if (x == NULL){
for (int i = 0; i<n; i++){
printf(" ");
}
printf("NULL\n");
return;
}
BST_printf(x->right, n + 1); //输出右子树
for (int i = 0; i<n; i++){ //输出长为n的" "空格
printf(" ");
}
if (n >= 0){
printf("%d-->\n", x->key); // 输出该点的数值
}
BST_printf(x->left, n + 1); //输出左子树
}
四.查询二叉搜索树
查找
对于二叉搜索树,最常用的操作就是查找树中的一个关键字了。给定指定树根的指针和关键字k,通过函数BST_search返回包含关键字k的结点的指针,不存在则返回NULL。
BST_Node* BST_tree::BST_search(BST_Node *x, int k){
if (x == NULL || k == x->key)
return x;
if (k < x->key)
return BST_search(x->left, k);
else
return BST_search(x->right, k);
}
查找最大关键字元素和最小关键字元素
利用二叉搜索树构造的性质,要查找二叉树中具有最小关键字的元素,只要从根结点开始,沿着各结点的left指针查找下去,知道遇到NULL时为止;查找二叉树的具有最大关键字的元素的方法和它对称相反。
对于高度为h的树,这两个过程的时间复杂度都是O(h).
BST_Node* BST_tree::BST_minnum(BST_Node* x){
while (x->left != NULL)
x = x->left;
return x;
}
BST_Node* BST_tree::BST_maxnum(BST_Node* x){
while (x->right != NULL)
x = x->right;
return x;
}
查找前驱和后继
如果所有的关键字均不相同,则某一结点x的后继既是具有大于key[x]中的关键字中最小值的那个结点;某一结点x的前驱既是具有小于key[x]中的关键字中最大值的那个结点。
根据二叉搜索树的结构,不用对关键字做任何比较,就可以找出某个结点的前驱和后继。
查找某个结点的后继有两种情况。一种情况是:如果结点x的右子树非空,则x的后继即右子树的最左结点(最小值),比如上图中的关键字为6的后继就是右子树的关键字最小值为10的结点。另一种情况是:如果结点x的右子树为空,且x有一个后继y,则y是x和y的最低公共祖先。前驱的情况和后继的情况相似且对称。比如说上图中的关键字为13的结点的后继就是关键字为16的结点,13和16的结点的最近公共祖先就是16.
如果二叉搜索树中某个结点有两个儿子,则其后继没有左儿子,其前驱没有右儿子。
BST_Node* BST_tree::BST_successor(BST_Node* x){
if (x->right != NULL)
return BST_minnum(x->right);
BST_Node* y = x->fa;
while(y!= NULL && x==y->right){
x = y;
y = y->fa;
}
return y;
}
BST_Node* BST_tree::BST_precursor(BST_Node* x){
if (x->left != NULL)
return BST_maxnum(x->left);
BST_Node* y = x->fa;
while (y != NULL && x == y->left){
x = y;
y = y->fa;
}
return y;
}
五.插入和删除
插入
为将一个新值v插入到二叉搜索树T中,可以调用函数BST_insert,传给该过程的参数是一个结点,并且有key[z]=v,left[z]=NULL,right[z]=NULL.该过程修改T和z的某些域,并把z插入到树中的适当的位置。
void BST_tree::BST_insert(BST_Node* z){
BST_Node* y = NULL;
BST_Node* x = this->root;
while (x != NULL){
y = x;
if (z->key < x->key)
x = x->left;
else
x = x->right;
}
z->fa = y;
if (y == NULL)
this->root = z;
else{
if (z->key < y->key)
y->left = z;
else
y->right = z;
}
}
删除
将给定的结点v从二叉搜索树中删除的过程以指向z的指针为参数,并考虑了下图中的三种情况。
- 如果z没有儿子结点,修改z的父结点的儿子域即可,将z直接删除就行,
- 如果z有一个儿子结点,则修改z的父亲结点的儿子域和z的儿子结点的父亲域,然后将z删除
- 如果z有两个儿子结点,则找到z的后继结点x,将x结点的值赋值给z结点,然后将x结点删除(这时候的x结点没有左儿子,可以采用a或者b方法中的一种即可)
BST_Node* BST_tree::BST_delete(BST_Node* z){
BST_Node *y, *x;
if (z->left == NULL || z->right == NULL)
y = z;
else
y = BST_successor(z);
if (y->left != NULL)
x = y->left;
else
x = y->right;
if (x != NULL)
x->fa = y->fa;
if (y->fa == NULL)
root = x;
else{
if (y == y->fa->left)
y->fa->left = x;
else
y->fa->right = x;
}
if (y != z){
z->key = y->key;
//copy y'data into z
}
return y
六.完整代码
#include<iostream>
using namespace std;
const int inf = 0x3f3f3f3f;
struct BST_Node{ //树结点
int key;
BST_Node *fa, *left, *right;
};
struct BST_tree{ //二叉搜索树(binnary search tree)
BST_Node *root; //二叉搜索树的根结点
void BST_inorder(BST_Node *x); //中序遍历输出一颗二叉搜索树
void BST_printf(BST_Node *x,int n=0); //逆时90度输出一颗二叉搜索树
BST_Node* BST_search(BST_Node *x,int k); //查找key值为k的树结点
BST_Node* BST_minnum(BST_Node* x); //查找以x为根结点的树的最小值
BST_Node* BST_maxnum(BST_Node* x); //查找以x为根结点的树的最大值
BST_Node* BST_successor(BST_Node* x); //查找x的后继结点
BST_Node* BST_precursor(BST_Node* x); //查找x的前驱结点
void BST_insert(BST_Node* x); //插入新的树结点
BST_Node* BST_delete(BST_Node* x); //删除树结点
}T;
void BST_tree::BST_inorder(BST_Node *x){ //中序遍历输出一颗二叉搜索树
if (x != NULL){
BST_inorder(x->left);
printf("%d ", x->key);
BST_inorder(x->right);
}
}
void BST_tree::BST_printf(BST_Node *x, int n){ //逆时90度输出一颗二叉搜索树
if (x == NULL){
for (int i = 0; i<n; i++){
printf(" ");
}
printf("NULL\n");
return;
}
BST_printf(x->right, n + 1); //输出右子树
for (int i = 0; i<n; i++){ //输出长为n的" "空格
printf(" ");
}
if (n >= 0){
printf("%d-->\n", x->key); // 输出该点的数值
}
BST_printf(x->left, n + 1); //输出左子树
}
BST_Node* BST_tree::BST_search(BST_Node *x, int k){
if (x == NULL || k == x->key)
return x;
if (k < x->key)
return BST_search(x->left, k);
else
return BST_search(x->right, k);
}
BST_Node* BST_tree::BST_minnum(BST_Node* x){
while (x->left != NULL)
x = x->left;
return x;
}
BST_Node* BST_tree::BST_maxnum(BST_Node* x){
while (x->right != NULL)
x = x->right;
return x;
}
BST_Node* BST_tree::BST_successor(BST_Node* x){
if (x->right != NULL)
return BST_minnum(x->right);
BST_Node* y = x->fa;
while(y!= NULL && x==y->right){
x = y;
y = y->fa;
}
return y;
}
BST_Node* BST_tree::BST_precursor(BST_Node* x){
if (x->left != NULL)
return BST_maxnum(x->left);
BST_Node* y = x->fa;
while (y != NULL && x == y->left){
x = y;
y = y->fa;
}
return y;
}
void BST_tree::BST_insert(BST_Node* z){
BST_Node* y = NULL;
BST_Node* x = this->root;
while (x != NULL){
y = x;
if (z->key < x->key)
x = x->left;
else
x = x->right;
}
z->fa = y;
if (y == NULL)
this->root = z;
else{
if (z->key < y->key)
y->left = z;
else
y->right = z;
}
}
BST_Node* BST_tree::BST_delete(BST_Node* z){
BST_Node *y, *x;
if (z->left == NULL || z->right == NULL)
y = z;
else
y = BST_successor(z);
if (y->left != NULL)
x = y->left;
else
x = y->right;
if (x != NULL)
x->fa = y->fa;
if (y->fa == NULL)
root = x;
else{
if (y == y->fa->left)
y->fa->left = x;
else
y->fa->right = x;
}
if (y != z){
z->key = y->key;
//copy y'data into z
}
return y;
}
int main(){
int num[] = { 16, 6, 18, 4, 13, 10, 14, 5, 3, 22, 23, 11, 20 };
BST_Node *temp;
int len = sizeof(num) / 4;
for (int i = 0; i < len; i++){
temp = new BST_Node();
temp->key = num[i];
T.BST_insert(temp);
}
T.BST_inorder(T.root);
printf("\n");
T.BST_printf(T.root);
//查找关键字为6,14,23的结点的后继
temp = T.BST_search(T.root, 6);
printf("%d\n", T.BST_successor(temp) == NULL ? -inf : T.BST_successor(temp)->key);
temp = T.BST_search(T.root, 14);
printf("%d\n", T.BST_successor(temp) == NULL ? -inf : T.BST_successor(temp)->key);
temp = T.BST_search(T.root, 23);
printf("%d\n", T.BST_successor(temp) == NULL ? -inf : T.BST_successor(temp)->key);
//查找关键字为6,20,3的结点的前驱
temp = T.BST_search(T.root, 6);
printf("%d\n", T.BST_precursor(temp) == NULL ? -inf : T.BST_precursor(temp)->key);
temp = T.BST_search(T.root, 20);
printf("%d\n", T.BST_precursor(temp) == NULL ? -inf : T.BST_precursor(temp)->key);
temp = T.BST_search(T.root, 3);
printf("%d\n", T.BST_precursor(temp) == NULL ? -inf : T.BST_precursor(temp)->key);
//删除关键字为14,18,6的结点
temp = T.BST_search(T.root, 14);
T.BST_delete(temp);
T.BST_inorder(T.root);
printf("\n");
T.BST_printf(T.root);
temp = T.BST_search(T.root, 18);
T.BST_delete(temp);
T.BST_inorder(T.root);
printf("\n");
T.BST_printf(T.root);
temp = T.BST_search(T.root, 6);
T.BST_delete(temp);
T.BST_inorder(T.root);
printf("\n");
T.BST_printf(T.root);
return 0;
}