# 二叉搜索树

## 定义数据结构

//树结点结构
struct Node {
int key;
Node* left;
Node* right;
Node* parent;
};

//树
struct Tree {
Node* root;
};


## 二叉树的遍历

//中序遍历
void inorder_tree_walk(Node* x) {
if (x != NULL) {
inorder_tree_walk(x->left);
cout << x->key << " ";
inorder_tree_walk(x->right);
}
}
//前序遍历
void preorder_tree_walk(Node* x) {
if (x != NULL) {
cout << x->key << " ";
preorder_tree_walk(x->left);
preorder_tree_walk(x->right);
}
}
//后续遍历
void postorder_tree_walk(Node* x) {
if (x != NULL) {
postorder_tree_walk(x->left);
postorder_tree_walk(x->right);
cout << x->key << " ";
}
}


## 查询指定结点值

//递归版
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* iterative_tree_search(Node* x, int k) {
while (x != NULL && k != x->key) {
if (k < x->key) {
x = x->left;
}
else {
x = x->right;
}
}
return x;
}



## 最大元素和最小元素

//找最小结点
Node* tree_minimum(Node* x) {
while (x->left != NULL) {
x = x->left;
}
return x;
}
//找最大结点
Node* tree_maximum(Node* x) {
while (x->right != NULL) {
x = x->right;
}
return x;
}


## 前驱和后继

6，它的后继就是右子树中最小的那个，也就是7。

//前驱
Node* tree_predecessor(Node* x) {
//如果左子树非空，则前驱是左子树中最大的结点
if (x->left != NULL) {
return tree_maximum(x->left);
}
//否则，找到父系结点中第一个使得它是其右子孙的结点
Node* y = x->parent;
while (y != NULL && y->left == x) {
x = y;
y = x->parent;
}
return y;
}

//后继
Node* tree_successor(Node* x) {
//如果右子树非空，则后继是右子树中的最左结点
if (x->right != NULL) {
return tree_minimum(x->right);
}
//否则，找到父系结点中第一个使得它是其左子孙的结点
Node* y = x->parent;
while (y != NULL && y->right == x) {
x = y;
y = x->parent;
}
return y;
}


## 插入

void tree_insert(Tree* T, Node* z) {
Node* y = NULL;  //用来记住父节点
Node* x = T->root;   //从根开始查找
while (x != NULL) {
y = x;   //记住要挂留的父节点
if (z->key < x->key) {   //在左子树中找
x = x->left;
}
else {
x = x->right;    //在右子树中找
}
}
z->parent = y;  //挂上去
if (y == NULL) {   //如果树是空的
T->root = z;
}
//父亲收养它
else if (z->key < y->key) {
y->left = z;
}
else {
y->right = z;
}
}


## 删除

• 如果z没有孩子结点，那么只是简单的把它删除掉，并且修改它的父节点指向空。

• 如果z只有一个孩子，那么将这个孩子提升到树中z的位置上，并修改z的父节点的孩子指针。

• 如果z有两个孩子，那么找到z的后继y（在右子树中），并让y占据z的位置。

这里有细分为两种情况：

• 如果y是z的右孩子，则直接把以y为根的子树放到z上，在让z的左子树成为y的左子树。

• 如果y不是z的右孩子，则先用y的右孩子来替换y，在用y替换z。

为了完成以上工作，额外定义一个函数transplant，它专门用来移植结点。它用一棵以v为根的子树来替换一棵以u为根的子树，结点u的双亲变为结点v的双亲，并且最后v成为u的双亲的相应孩子。

代码如下：

void transplant(Tree* T, Node* u, Node* v) {
if (u->parent == NULL) {   //如果被替换的是树根，则要让其成为树根
T->root = v;
}
else if (u == u->parent->left) {   //如果被替换的那个结点是其父节点的左孩子
u->parent->left = v;
}
else {                         //否则是右孩子
u->parent->right = v;
}
if (v != NULL) {         //指向父节点
v->parent = u->parent;
}
}

void tree_delete(Tree* T, Node* z) {
//对应第一种和第二种情况
if (z->left == NULL) {
transplant(T, z, z->right);
}
else if (z->right == NULL) {
transplant(T, z, z->left);
}
//对应第三种情况
else {
Node* y = tree_minimum(z->right);
if (y->parent != z) { //如果y不是z的直接右孩子
transplant(T, y, y->right);
y->right = z->right;
y->right->parent = y;
}
transplant(T, z, y);
y->left = z->left;
y->left->parent = y;
}
}


posted @ 2020-07-13 19:36  裏表異体  阅读(182)  评论(0编辑  收藏