如果还是不太理解的话, 可以看看这个美国旧金山大学 CS 做的一个算法可视化. Binary Search Tree Visualization (usfca.edu) 在这个网站上详细地看到 BST 中每一步的操作. 做的很好, 不妨去玩玩!
代码实现 Implement下面的是 BST 类的完整实现.
class TreeNode{public: TreeNode(int m_data) : data(m_data) {} int data; TreeNode *left = nullptr; TreeNode *right = nullptr; TreeNode *parent = nullptr; bool isLeaf() {return left == nullptr && right == nullptr; }};class BinarySearchTree{public: void insert(const int item) {TreeNode *scan = root;TreeNode *prev = root;while (scan != nullptr){prev = scan;scan = item < scan->data ? scan->left : scan->right;}TreeNode *newNode = new TreeNode(item);if (root){(item < prev->data ? prev->left : prev->right) = newNode;newNode->parent = prev;}else{root = newNode;}return; } void remove(const int item) {TreeNode *delNode = p_find(item);if (delNode)p_remove(delNode); } void remove_ref(const int item) {TreeNode *&delNode = p_find_ref(item);if (delNode)p_remove_ref(delNode); } int find(const int item) {TreeNode *node = p_find(item);return node ? node->data : -1; } int pred(const int item) {TreeNode *node = p_pred(item);return node ? node->data : -1; } int succ(const int item) {TreeNode *node = p_succ(item);return node ? node->data : -1; } void print() {p_printAll(root);putchar('\n'); }private: TreeNode *root = nullptr; const TreeNode *empty = nullptr; void p_printAll(TreeNode *node) {if (!node)return;p_printAll(node->left);printf("%d ", node->data);p_printAll(node->right); } void p_remove(TreeNode *delNode) {if (delNode->isLeaf()) // case1{if (delNode->parent){// judge which pointer of node to modifyif (delNode == delNode->parent->left){delNode->parent->left = nullptr;}else{delNode->parent->right = nullptr;}}else // when root == delNode;{root = nullptr;}delete delNode;}else if (delNode->left == nullptr) // case 2{// basically same as aboveif (delNode->parent){if (delNode == delNode->parent->left){delNode->parent->left = delNode->right;}else{delNode->parent->right = delNode->right;}}else // root == delNode;{root = delNode->right;root->parent = nullptr;}delete delNode;}else if (delNode->right == nullptr){// same as aboveif (delNode->parent){if (delNode == delNode->parent->left){delNode->parent->left = delNode->left;}else{delNode->parent->right = delNode->left;}}else // root == delNode;{root = delNode->left;root->parent = nullptr;}delete delNode;}else{// case3TreeNode *succNode = p_succ(delNode);delNode->data = https://www.huyubaike.com/biancheng/succNode->data;p_remove(succNode);} } void p_remove_ref(TreeNode *&delNodeRef) {TreeNode *delPtr = delNodeRef;if (delNodeRef->isLeaf()){delNodeRef = nullptr;}else if (!delNodeRef->left || !delNodeRef->right){TreeNode *subTree = max(delNodeRef->right, delNodeRef->left);if (root == delNodeRef)subTree->parent = nullptr;delNodeRef = subTree;}else{TreeNode *succNode = p_succ(delNodeRef);delNodeRef->data = succNode->data;p_remove(succNode);}delete delPtr; } TreeNode *p_find(const int item) {TreeNode *scan = root;while (scan != nullptr && scan->data != item){scan = item < scan->data ? scan->left : scan->right;}return scan; } TreeNode *&p_find_ref(const int item) {TreeNode *scan = root;TreeNode *prev = nullptr;while (scan != nullptr && scan->data != item){prev = scan;scan = item < scan->data ? scan->left : scan->right;}if (root->data == item) return root;if (!scan) return (TreeNode *&) empty;return prev->left == scan ? (*prev).left : (*prev).right; } TreeNode *p_pred(int item) {TreeNode *itemNode = p_find(item);if (!itemNode)return nullptr;if (itemNode->left){return p_max(itemNode->left);}else{TreeNode *scan = itemNode->parent;while (scan && scan->left == itemNode){scan = scan->parent;itemNode = itemNode->parent;}return scan;} } TreeNode *p_succ(int item) {TreeNode *itemNode = p_find(item);if (!itemNode)return nullptr;if (itemNode->right){return p_min(itemNode->right);}else{TreeNode *scan = itemNode->parent;while (scan && scan->right == itemNode){scan = scan->parent;itemNode = itemNode->parent;}return scan;} } TreeNode *p_succ(TreeNode *itemNode) {if (itemNode->right){return p_min(itemNode->right);}else{TreeNode *scan = itemNode->parent;while (scan && scan->right == itemNode){scan = scan->parent;itemNode = itemNode->parent;}return scan;} } TreeNode *p_max(TreeNode *node) {if (!node)return nullptr;while (node->right){node = node->right;}return node; } TreeNode *p_min(TreeNode *node) {if (!node)return nullptr;while (node->left){node = node->left;}return node; }};
结构分析 Analysis总结上文提到的所有操作, 对 BST 的每一步操作都是向树的深处再进一层, 而每一次进入一颗子树都意味着筛选掉了当前树中的一半节点, 对剩下来的一半节点继续操作.(二分思想)
由此, 我们可以容易的的得到一个结论: BST 中的最大查找次数取决于 BST 的最大深度, 即树高. 在最好情况下, 一个有着 n 个节点的树, 他的深度最小为 \(\log_2 n\). 此时, BST 可以达到最高效率.
推荐阅读
- 原神掣电树传送点怎么开启
- 原神梦境与树任务怎么完成
- 野火 STM32MP157 开发板内核和设备树的编译烧写
- 原神探索莎兰树的梦任务怎么完成
- FHQ Treap 详解
- 原神3.0成就众花园中的一棵核桃树怎么完成
- 原神梦境与树前往指定地点任务怎么完成
- 树的邻接矩阵、双亲孩子表示法…… C++ 不知树系列之初识树
- C#实现生成Markdown文档目录树
- 给 hugo 博客添加搜索功能