二叉搜索树
二叉搜索树(BST)是能够高效进行以下操作的数据结构
(STL中set就是使用了二叉搜索树来维护的)
- 插入一个数值
- 查询是否包含某个数值
- 删除某个数值
二叉搜索树的存储特性,所有的节点都满足左子树上的所有节点都比自己小,右子树上的所有节点都比自己大,并且树中没有重复的值。
一般有3种操作,插入,查找和删除,查找和删除都比较简单,只需要往比较关键值的大小,不断往左右子树寻找即可,直到找到正确的位置
例如下图,是一棵二叉搜索树
如果要删除10这个节点,那么应该从10的子树中提一个节点上来,一般来说,删除节点需要根据下面几种情况来分别进行处理
- 需要删除的节点没有左儿子,那么就把右儿子提上去
- 需要删除的节点有左儿子并且没有该左儿子没有右儿子,那么就把左儿子提上去
- 如果以上两点不满足,那就找左儿子子孙中最大的节点提上去
不管进行什么操作,时间和树的高度成正比,假设有nnn个元素,时间复杂度为O(log n)O(log\,n)O(logn)
实现操作,靠一个链表结构来表示,每一个节点都包含左右指向左右儿子的指针
struct node {
int val;
node *left, *right;
};
node *root = NULL;
插入操作
node *insert(node *p, int x) {
if(p == NULL) { //如果当前节点为空,则找到了插入的位置
node *q = new node;
q->val = x;
q->left = q->right = NULL;
return q;
}else {
if(p->val > x) p->left = insert(p->left, x); //如果小于则往左子树插入
else p-> right = insert(p->right, x); //往右子树插入
return p;
}
}
查找操作
bool find(node *p, int x) {
if(p == NULL) return false; //找到叶子节点都没有 则返回0
else if(x == p->val) return true; //找到
else if(x < p->val) return find(p->left, x); //小于,递归左子树
else return find(p->right, x); //递归右子树
}
删除操作
node *remove(node *p, int x) {
if(p == NULL) return NULL;
else if(x < p -> val) p -> left = remove(p -> left, x); //找到删除的节点
else if(x > p -> val) p -> right = remove(p -> right, x);
else if(p -> right == NULL) { //如果右子树为空,那么左边都比它本身小,删除即可
node *q = p -> right;
delete p;
return q;
}else if(p -> left -> right == NULL) { //左子树的右儿子为空,那么本身就是最大的,同样删除即可
node *q = p -> left;
q -> right = p -> right;
delete p;
return q;
}else { //找出左子树中,最大的节点放上去
node *q;
for(q = p -> right; q -> right -> right != NULL; q = q -> right);
node *r = q -> right;
q -> right = r -> left;
r -> left = p -> left;
r -> right = p -> right;
delete p;
return r;
}
return p;
}
完整操作
#include <iostream>
using namespace std;
struct node {
int val;
node *left, *right;
};
node *root = NULL;
node *insert(node *p, int x) {
if(p == NULL) {
node *q = new node;
q -> val = x;
q -> left = q -> right = NULL;
return q;
}else {
if(p -> val > x) p -> left = insert(p -> left, x);
else p -> right = insert(p -> right, x);
return p;
}
}
bool find(node *p, int x) {
if(p == NULL) return false;
else if(x == p -> val) return true;
else if(x < p -> val) return find(p -> left, x);
else return find(p -> right, x);
}
node *remove(node *p, int x) {
if(p == NULL) return NULL;
else if(x < p -> val) p -> left = remove(p -> left, x);
else if(x > p -> val) p -> right = remove(p -> right, x);
else if(p -> right == NULL) {
node *q = p -> right;
delete p;
return q;
}else if(p -> left -> right == NULL) {
node *q = p -> left;
q -> right = p -> right;
delete p;
return q;
}else {
node *q;
for(q = p -> right; q -> right -> right != NULL; q = q -> right);
node *r = q -> right;
q -> right = r -> left;
r -> left = p -> left;
r -> right = p -> right;
delete p;
return r;
}
return p;
}
int main() {
int n;
cin >> n;
for(int i = 1, j; i <= n; i++) { //插入n个元素
cin >> j;
root = insert(root, j);
}
int x, y;
cin >> x >> y;
root = remove(root, y); //删除节点t
bool f = find(root, x); //查找节点x
if(f) cout << "yes\n";
else cout << "no\n";
return 0;
}
树的遍历
/**
遍历结果保存在vector动态数组中
**/
void preorder(node *root, vector <int> &path) { //先序遍历
if(root != NULL) {
path.push_back(root -> val);
preorder(root -> right, path);
preorder(root -> left, path);
}
}
void inorder(node *root, vector <int> &path) { //中序遍历(从大到小)
if(root != NULL) {
inorder(root -> right, path);
path.push_back(root -> val);
inorder(root -> left, path);
}
}
void postorder(node *root, vector <int> &path) { //后序遍历
if(root != NULL) {
postorder(root -> right, path);
postorder(root -> left, path);
path.push_back(root -> val);
}
}