文章目录
Binary Search Tree, 简称 BST,也称二叉排序树或二叉查找树。
特点:
-
任一结点 > 其左子树的所有结点,
并且< 其右子树的所有结点; -
结点的左、右子树,也是二叉排序树;
-
每个结点键值唯一(不能重复)
重要性质:
- 中序遍历二叉排序树得到递增序列
所以判断1棵二叉树是否是二叉排序树?
只要中序遍历,得到递增序列才是。
插入
- 若当前树为空,则新结点为根
- 若当前树不空,
将待插入x与根比较;- 若x等于根,不用插入
- 若x大于根,则去右子树(找位置);
- 若x小于根,则去左子树(找位置);
可以总结为:
插入之前,先查找:
- 若找到,不用插入
- 若找不到,则在到达的空位置处,放入x;
所以最新插入的结点,一定是叶子;
void insert(int k){
Node *x=root; //已有树的根结点
Node *y=NULL; //x的父结点
Node *z; //z为左右子树空的实参,键值为 k
z=(Node *)malloc(sizeof(Node));
z->key=k;
z->l=z->r=NULL;
while (x!=NULL) {
y=x;
if (z->key<x->key) x=x->l;
else x=x->r;
}
z->p=y;
if (y==NULL) root=z; //空树,直接加
else {
if (z->key<y->key) y->l=z;
else y->r=z;
}
}
查找
- 从根结点开始,如果树为空,则返回 NULL
- 如果非空,从根结点开始,比较待检索的键值
-
若相等,则成功;
-
若小于根,
则去根的左子树; -
若大于根,
则去根的右子树,
-
Node * find(Node *u, int k){
while (u!=NULL && k!=u->key){
if (k<u->key) u=u->l;
else u=u->r;
}
return u;
}
删除
考虑三种情况:
- ①要删除叶子结点
直接删除,并将父结点指针置为 NULL
- ② 删除只有1个孩子的结点
将父结点指针指向要删除结点的孩子结点
- ③ 删除有左右子树的结点
用另一个结点替代删除的结点:- 右子树的最小元素 或者 左子树的最大元素
Node * minNode(Node *u){
while (u->l!=NULL) u=u->l;
return u;
}
//确定删除的结点,这里选择 u的后继:大于 u.key的最小key的结点。
Node * deleteNode(Node *u){
if (u->l==NULL || u->r==NULL) return u; //没有子结点或者只有1个
if (u->r!=NULL) return minNode(u->r); //2个子结点,如果右子树不空,那么后继选择右子树最小值
//如果右子树空,那么后继一定为 u最底层的祖先,并且后继的左孩子也是u的一个祖先
//在后继节点处,如果节点是整棵树的根节点的右边,并且这个节点没有右子树,则这个节点的后继节点为null。
Node *y=u->p;
while (y!=NULL && u==y->r){
u=y;
y=y->p;
}
return y;
}
void Delete(Node *u){
Node *y=deleteNode(u);
Node *x; //y的子结点
if (y->l!=NULL) x=y->l; //y有左子结点,x为 y的左子结点
else x=y->r; //y有右子结点,x为 y的右子结点
if (x!=NULL) x->p=y->p; //从父结点上,x替代 y
if (y->p==NULL) root=x; //如果y是根,那么x替代 y成为根
else {
if (y==y->p->l) y->p->l=x; //y为左子结点,x替代为左子结点
else y->p->r=x; //y为右子结点,x替代为右子结点
}
if (y!=u) u->key=y->key; //将 y的 key复制到 u中
free(y);
}
平均检索长度 ASL
比较次数:不大于树的深度
最坏平均查找长度ASL:(n+1)/2
最好ASL:log2(n) (参考二分查找)
所有操作的复杂度都是 O(logn)
完整代码
所有操作的复杂度都是 O(logn)
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
struct Node{
int key;
Node *r,*l,*p;
};
Node *root;
void insert(int k){
Node *x=root;
Node *y=NULL;
Node *z;
z=(Node *)malloc(sizeof(Node));
z->key=k;
z->l=z->r=NULL;
while (x!=NULL) {
y=x;
if (z->key<x->key) x=x->l;
else x=x->r;
}
z->p=y;
if (y==NULL) root=z;
else {
if (z->key<y->key) y->l=z;
else y->r=z;
}
}
Node * find(Node *u, int k){
while (u!=NULL && k!=u->key){
if (k<u->key) u=u->l;
else u=u->r;
}
return u;
}
Node * minNode(Node *u){
while (u->l!=NULL) u=u->l;
return u;
}
Node * deleteNode(Node *u){
if (u->l==NULL || u->r==NULL) return u;
if (u->r!=NULL) return minNode(u->r);
Node *y=u->p;
while (y!=NULL && u==y->r){
u=y;
y=y->p;
}
return y;
}
void Delete(Node *u){
Node *y=deleteNode(u);
Node *x;
if (y->l!=NULL) x=y->l;
else x=y->r;
if (x!=NULL) x->p=y->p;
if (y->p==NULL) root=x;
else {
if (y==y->p->l) y->p->l=x;
else y->p->r=x;
}
if (y!=u) u->key=y->key;
free(y);
}