二叉排序树
二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),亦称二叉搜索树,是数据结构中的一类。
二叉排序树定义如下:
(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
性质
- 左子树 < 根节点
- 右子树 > 根节点
- 中序遍历的结果,是一个有序序列
数据结构就是定义一种性质,并且维护这种性质
插入操作
- 插入的新节点,一定会作为叶子节点
- 插入顺序会影响最终的树形结构
不同的树形结构,查找效率不同
删除操作
- 删除度为0的节点,直接删除
- 删除度为1的节点,把【孤儿子树】挂到被删除节点的父节点下
- 删除度为2的节点,可以转换为删除度为1的节点
对于度为2的节点:
- 前驱:左子树最大值
- 后继:右子树最小值
先找出待删除节点的前驱节点,将前驱节点的值赋予待删除结点,此时问题就转换为从待删除节点的左子树中删除前驱节点,前驱节点一定不是度为2的点。
二叉搜索树上的基本操作所花费的时间与这棵树的高度成正比。对于一个有 n 个结点的二叉搜索树中,这些操作的最优时间复杂度为 O(log n),最坏为 O(n)。随机构造这样一棵二叉搜索树的期望高度为 O(log n)。
C语言实现二叉排序树
#include <stdio.h>
#include <stdlib.h>
#define KEY(n) (n ? n->val : 0)
typedef struct Node {
int val;
struct Node *l, *r;
}Node;
Node *get_new_node(int val) {
Node *p = (Node *)malloc(sizeof(Node));
p->val = val;
p->l = NULL;
p->r = NULL;
return p;
}
//插入操作
Node *insert(Node *root, int val) {
if (root == NULL) return get_new_node(val);
// 如果当前树中已存在该值节点,则不重复插入
if (root->val == val) return root;
//如果插入的值大于当前节点,则到当前节点的右子树中插入,否则去左子树中插入
if (val > root->val) root->r = insert(root->r, val);
else root->l = insert(root->l, val);
return root;
}
//删除操作
Node *erase(Node *root, int val) {
if (root == NULL) return root;
if (root->val > val) {
root->l = erase(root->l, val);
} else if (root->val < val){
root->r = erase(root->r, val);
} else {
//如果待删除节点是度为0或者度为1的节点
if (root->l == NULL || root->r == NULL) {
Node *temp = root->l ? root->l : root->r;
free(root);
return temp;
} else {
//如果待删除结点是度为2的结点,先找到待删除结点的前驱结点
Node *temp = root->l;
while(temp->r) temp = temp->r;
//将待删除节点的值变为其前驱节点的值
root->val = temp->val;
//此时问题变成删除temp节点
root->l = erase(root->l, temp->val);
}
}
return root;
}
//查询操作
int search(Node *root, int val) {
// 返回-1表示未能找到
if (root == NULL) return -1;
if (root->val == val) return 1;
if (val < root->val) return search(root->l, val);
return search(root->r, val);
}
//前序遍历
void in_order(Node *root) {
if (root == NULL) return ;
printf("%d ", root->val);
in_order(root->l);
in_order(root->r);
return ;
}
//中序遍历
void pre_order(Node *root) {
if (root == NULL) return ;
pre_order(root->l);
printf("%d ", root->val);
pre_order(root->r);
return ;
}
//后序遍历
void post_order(Node *root) {
if (root == NULL) return ;
post_order(root->l);
post_order(root->r);
printf("%d ", root->val);
return ;
}
void order(Node *root) {
printf("in_order = [");
in_order(root);
printf("]\n");
printf("pre_order = [");
pre_order(root);
printf("]\n");
printf("post_order = [");
post_order(root);
printf("]\n");
return ;
}
//按前序遍历输出每个节点的值及其左右节点的值
void output(Node *root) {
if (root == NULL) return ;
printf("(%d, %d, %d)\n", KEY(root), KEY(root->l), KEY(root->r));
output(root->l);
output(root->r);
return ;
}
//销毁树
void clear(Node *root) {
if (root == NULL) return ;
clear(root->l);
clear(root->r);
free(root);
return ;
}
int main() {
Node *root = NULL;
int op, val;
while(~scanf("%d%d", &op, &val)) {
if (op == -1) break;
switch(op) {
case 0: {
printf("insert %d to tree\n", val);
root = insert(root, val);
} break;
case 1: {
printf("erase %d from tree\n", val);
root = erase(root, val);
} break;
case 2: {
printf("search %d, result : %d\n", val, search(root, val));
} break;
}
if (op == 0 || op == 1) {
output(root);
}
printf("--------------\n");
}
order(root);
clear(root);
return 0;
}