二叉排序树基础知识
二叉排序树
名称:二叉排序树、二叉搜索树
性质:1. 左子树 < 根节点
2. 右子树 > 根节点
二叉排序树的中序遍历是一个升序数组。
二叉排序树解决排名相关的检索需求。
二叉排序树的插入
依次将待插入节点和当前节点比较,比其大则接着和右子树比较,小则接着和左子树比较,直到左子树或右子树为空,则插入相应的位置。
二叉排序树的删除
删除度为0的节点(叶子节点)
直接删除即可。
删除度为1的节点
度为1的节点即该节点有一个孩子,将该节点删除,然后将孩子挂在爷爷节点(删除节点的父节点)下方即可。
删除度为2的节点
前驱:整个二叉树中小于该节点的最大节点。即左子树的最大值。
后继:整个二叉树中大于该节点的最小节点。即右子树的最小值。
某个节点的前驱或后继,一定是度为0或度为1的节点,不可能是度为2的节点。
要删除某个度为2的节点时,首先找到该节点的前驱或后继,将前驱或后继放到要删除节点的位置,然后删除掉前驱或后继原来的位置(该位置一定是度为0或度为1的节点)。
总结:删除度为2的节点,找到前驱或后继后转换为删除度为0或1的节点。
二叉树删除与插入操作代码演示
#include <iostream>
using namespace std;
//二叉树定义
struct Node {
Node(int key = 0, Node *left = nullptr, Node *right = nullptr)
: key(key), left(left), right(right){};
int key;
Node *left, *right;
};
//初始化二叉树
Node *getNewNode(int key) {
return new Node(key);
}
//二叉树插入
Node *insert(Node *root, int key) {
if (root == nullptr) return getNewNode(key);
if (root->key == key) return root;
if (key < root->key) root->left = insert(root->left, key);
else root->right = insert(root->right, key);
return root;
}
//寻找前驱节点
Node *getPrecursor(Node *root) {
Node *node = root->left;
while (node->right) node = node->right;
return node;
}
//二叉树删除操作
Node *erase(Node *root, int key) {
if (root == nullptr) return root; //递归边界
if (key < root->key) root->left = erase(root->left, key);
else if (key > root->key) root->right = erase(root->right, key);
else { //当前节点为要删除的节点
if (root->left == nullptr || root->right == nullptr) {
//度为0和度为1的节点都可以用这个条件表示
Node *temp = root->left ? root->left : root->right;
delete root;
return temp;
}
else {
//要删除度为2的节点
Node *pre = getPrecursor(root);
root->key = pre->key;
root->left = erase(root->left, pre->key);
}
}
return root;
}
void clear(Node *root) {
//要删除整棵树
if (root == nullptr) return;
clear(root->left);
clear(root->right);
delete root;
return;
}
void output(Node *root) {
//递归输出一棵树
if (root == nullptr) return ;
output(root->left);
cout << root->key << " ";
output(root->right);
return;
}
int main() {
int op, val;
Node *root;
while (cin >> op >> val) {
switch (op) {
case 0: root = insert(root, val); break;
case 1: root = erase(root, val); break;
}
output(root); cout << endl;
}
return 0;
}
代码编程小技巧:1. 删除度为0和度为1的节点可以同时表示;2. 前驱节点直接从左子树一直向右找;3. 递归插入,递归删除。