一,基础概念
BST树,英文全称:Binary Search Tree,被称为二叉查找树或二叉搜索树。
如果一个二叉查找树非空,那么它具有如下性质:
1.左子树上所有节点的值小于根节点的值,节点上的值沿着边的方向递减。
2.右子树上所有节点的值大于根节点的值,节点上的值沿着边的方向递增。
3.非空的左子树和右子树也分别是二叉查找树。
4.按照中序遍历(左子树->根节点->右子树)的方式遍历该二叉查找树,可以得到一个递增的有序序列。
~来个复杂点的热热身~
该BST树的中序遍历结果:7 15 17 22 27 30 45 60 75
注意,BST树的结构不是一次性立即生成的,而是基于查找过程逐渐生成的。在查找过程中,当树中的节点元素不等于被查找值时,才进行插入节点的操作。
使用二叉查找树的好处
如果BST树是一棵平衡二叉树,那么在BST树上进行插入和删除操作的速度会很快。
由于BST树的特殊结构,导致在上面搜索元素的时候特别高效。
使用二叉查找树的缺点
BST树的最终形状依赖于插入操作的顺序,导致BST树可以退化成单链表(如果单调递减式的插入元素),后面会讲到AVL树,可以规避此缺点。
二,BST树的基本操作
查找节点:
1.从树的根节点开始移动。
2.如果被查找值小于当前节点,则向左移动。
3.如果被查找值大于当前节点,则向右移动。
插入节点:
1.先执行查找操作,来确定新节点的位置。
2.确认位置后,插入新节点,新节点成为叶子节点。
删除节点:
从BST树删除节点时,我们关心的是保持树的其余节点以正确的顺序排列。
删除节点的实际操作是将节点替换为NULL。
根据删除节点的位置不同,分下面三种情况:
(1)要删除的节点是叶子节点。简单执行删除操作。
(2)如果节点只有一个子节点。删除后,用子节点填充它原来的位置。
(3)如果节点有两个子节点。根据大小,将它和左子树的最大节点交换,或者和右子树的最小节点交换。因为左子树的最大节点是叶子节点,没有右子节点且不会继续扩展,右子树的最小节点也是叶子节点,没有左子节点且不会继续扩展。
三,BST树的代码实现
代码样例中的BST树采用的是链式存储实现,代码中节点的初始化和一般的二叉树代码类似,由数据域、左指针、右指针构成。
遍历顺序:1->3->4->6->7->8->10->14
Python代码实现:
#初始化节点
class Node:
def __init__(self, key):
self.key = key
self.left = None
self.right = None
#中序遍历
def inorder(root):
if root is not None:
inorder(root.left)
print(str(root.key) + "->", end=' ')
inorder(root.right)
#插入节点
def insert(node, key):
if node is None:
return Node(key)
if key < node.key:
node.left = insert(node.left, key)
else:
node.right = insert(node.right, key)
return node
def minValueNode(node):
current = node
while(current.left is not None):
current = current.left
return current
#删除节点
def deleteNode(root, key):
if root is None:
return root
if key < root.key:
root.left = deleteNode(root.left, key)
elif(key > root.key):
root.right = deleteNode(root.right, key)
else:
if root.left is None:
temp = root.right
root = None
return temp
elif root.right is None:
temp = root.left
root = None
return temp
#如果被删除节点有两个子节点
temp = minValueNode(root.right)
root.key = temp.key
root.right = deleteNode(root.right, temp.key)
return root
root = None
root = insert(root, 8)
root = insert(root, 3)
root = insert(root, 1)
root = insert(root, 6)
root = insert(root, 7)
root = insert(root, 10)
root = insert(root, 14)
root = insert(root, 4)
print("Inorder traversal: ", end=' ')
inorder(root)
print("\nDelete 10")
root = deleteNode(root, 10)
print("Inorder traversal: ", end=' ')
inorder(root)
运行结果:
Inorder traversal: 1-> 3-> 4-> 6-> 7-> 8-> 10-> 14->
Delete 10
Inorder traversal: 1-> 3-> 4-> 6-> 7-> 8-> 14->
C++代码实现:
#include <iostream>
using namespace std;
//初始化节点
struct node {
int key;
struct node* left, * right;
};
//创建新的节点
struct node* newNode(int item) {
struct node* temp = (struct node*)malloc(sizeof(struct node));
temp->key = item;
temp->left = temp->right = NULL;
return temp;
}
//中序遍历
void inorder(struct node* root) {
if (root != NULL) {
inorder(root->left);
cout << root->key << " -> ";
inorder(root->right);
}
}
//插入节点
struct node* insert(struct node* node, int key) {
if (node == NULL) return newNode(key);
if (key < node->key)
node->left = insert(node->left, key);
else
node->right = insert(node->right, key);
return node;
}
struct node* minValueNode(struct node* node) {
struct node* current = node;
while (current && current->left != NULL)
current = current->left;
return current;
}
//删除节点
struct node* deleteNode(struct node* root, int key) {
if (root == NULL) return root;
if (key < root->key)
root->left = deleteNode(root->left, key);
else if (key > root->key)
root->right = deleteNode(root->right, key);
else {
if (root->left == NULL) {
struct node* temp = root->right;
free(root);
return temp;
}
else if (root->right == NULL) {
struct node* temp = root->left;
free(root);
return temp;
}
//如果被删除节点有两个子节点
struct node* temp = minValueNode(root->right);
root->key = temp->key;
root->right = deleteNode(root->right, temp->key);
}
return root;
}
int main() {
struct node* root = NULL;
root = insert(root, 8);
root = insert(root, 3);
root = insert(root, 1);
root = insert(root, 6);
root = insert(root, 7);
root = insert(root, 10);
root = insert(root, 14);
root = insert(root, 4);
cout << "Inorder traversal: ";
inorder(root);
cout << "\nAfter deleting 10\n";
root = deleteNode(root, 10);
cout << "Inorder traversal: ";
inorder(root);
}
运行结果:
Inorder traversal: 1 -> 3 -> 4 -> 6 -> 7 -> 8 -> 10 -> 14 ->
After deleting 10
Inorder traversal: 1 -> 3 -> 4 -> 6 -> 7 -> 8 -> 14 ->
四,参考阅读
https://courses.engr.illinois.edu/cs225/sp2019/notes/bst/
https://www.programiz.com/dsa/binary-search-tree