📅  最后修改于: 2023-12-03 15:26:09.184000             🧑  作者: Mango
二叉搜索树(Binary Search Tree,简称BST)是一种常见的树型数据结构,也是一种基础的搜索算法。BST中,每个节点都只有最多两个子节点,并且左子树上所有的节点的值均小于该节点的值,右子树上所有节点的值均大于该节点。通过这种方式构建的二叉树,能够支持快速的查找、插入、删除操作。
BST的实现需要满足以下性质:
通过满足这些性质,我们可以保证在每次操作时,都可以通过比较目标值和节点值的大小来决定向左还是向右搜索,从而加快搜索的速度。
我们可以采用两种方式来实现BST,即指针实现和数组实现。
指针实现方式实际上就是构建一棵树,每个节点都是一个指针。每个节点包含一个key和value,以及左右子节点的指针。插入、查找和删除时,都是通过比较key的大小来判断进入左子树还是右子树。
BST中的插入操作非常简单,只要按照二叉搜索树的性质递归比较节点的大小,然后将其插入到正确的位置即可。
以下是一个示例代码:
class TreeNode {
public:
TreeNode(int key, int value) : key(key), value(value), left(nullptr), right(nullptr) {}
int key;
int value;
TreeNode* left;
TreeNode* right;
};
class BST {
public:
void insert(int key, int value) {
root = insert(root, key, value);
}
private:
TreeNode* insert(TreeNode* root, int key, int value) {
if (!root) {
return new TreeNode(key, value);
}
if (key > root->key) {
root->right = insert(root->right, key, value);
} else if (key < root->key) {
root->left = insert(root->left, key, value);
}
return root;
}
TreeNode* root;
};
查询操作与插入操作的实现方式类似,同样是通过比较key的大小,递归查找节点。
以下是一个示例代码:
class BST {
public:
int find(int key) {
TreeNode* node = find(root, key);
if (!node) {
return -1;
}
return node->value;
}
private:
TreeNode* find(TreeNode* root, int key) {
if (!root) {
return nullptr;
}
if (key > root->key) {
return find(root->right, key);
} else if (key < root->key) {
return find(root->left, key);
} else {
return root;
}
}
TreeNode* root;
};
删除操作是BST中比较难实现的,需要考虑多种情况,包括3种情况:
以下是一个示例代码:
class BST {
public:
void remove(int key) {
root = remove(root, key);
}
private:
TreeNode* remove(TreeNode* root, int key) {
if (!root) {
return nullptr;
}
if (key > root->key) {
root->right = remove(root->right, key);
} else if (key < root->key) {
root->left = remove(root->left, key);
} else {
if (!root->left) {
auto temp = root->right;
delete root;
return temp;
} else if (!root->right) {
auto temp = root->left;
delete root;
return temp;
} else {
auto temp = root->left;
while (temp->right) {
temp = temp->right;
}
root->key = temp->key;
root->value = temp->value;
root->left = remove(root->left, temp->key);
}
}
return root;
}
TreeNode* root;
};
我们还可以采用数组的方式来实现BST,数组实现的好处是可以节约空间,避免使用指针和动态内存分配。我们可以按照层序遍历的方式来将二叉搜索树建立在一个数组中。
具体实现的方式是:假设根节点在数组下标0,那么对于任意一个节点i,左子节点在2i+1下标处,右子节点在2i+2下标处。
下面是一个数组实现的示例代码:
class BST {
public:
void insert(int key, int value) {
if (root.empty()) {
root.resize(1, {-1, -1, -1});
root[0] = {key, value, -1};
} else {
int i = 0;
while (true) {
if (key > root[i].key) {
if (root[i].right == -1) {
root[i].right = root.size();
root.emplace_back(key, value, -1);
break;
}
i = root[i].right;
} else if (key < root[i].key) {
if (root[i].left == -1) {
root[i].left = root.size();
root.emplace_back(key, value, -1);
break;
}
i = root[i].left;
} else {
root[i].value = value;
break;
}
}
}
}
int find(int key) {
int i = 0;
while (i < root.size() && root[i].key != -1) {
if (key > root[i].key) {
i = root[i].right;
} else if (key < root[i].key) {
i = root[i].left;
} else {
return root[i].value;
}
}
return -1;
}
void remove(int key) {
auto find_node = [&]() -> int {
int i = 0;
while (i < root.size() && root[i].key != -1) {
if (key > root[i].key) {
i = root[i].right;
} else if (key < root[i].key) {
i = root[i].left;
} else {
return i;
}
}
return -1;
};
int idx = find_node();
if (idx == -1) {
return;
}
if (root[idx].left == -1 && root[idx].right == -1) {
root[idx] = {-1, -1, -1};
} else if (root[idx].left == -1) {
root[idx] = root[root[idx].right];
remove(root[idx].key);
} else if (root[idx].right == -1) {
root[idx] = root[root[idx].left];
remove(root[idx].key);
} else {
int i = root[idx].left;
while (root[i].right != -1) {
i = root[i].right;
}
root[idx] = root[i];
remove(root[i].key);
}
}
private:
struct Node {
int key, value, left, right;
};
std::vector<Node> root;
};
二叉搜索树是一种非常常见的数据结构,它能够快速地进行插入、查找和删除操作。我们可以采用指针和数组两种方式来实现BST。指针实现更加直接,代码也更加简洁,但是对于大规模的数据,动态内存分配的开销比较大。数组实现则可以避免这个问题,但是在插入和删除操作时需要进行数组的扩容和缩容操作,比较繁琐。在实际开发中,我们根据实际需要选择更加适合的方式来实现。