目录
1.定义
初始化
插入
查找
删除
完整代码
2.运用
K 模型和 KV 模型详解
K 模型
KV 模型
代码解释
为了更好地理解 map 和 set 的特性,和后面讲解查找效率极高的平衡搜索二叉树,和红黑树去实现模拟,所以决定在这里对搜索二叉树进行一个讲解~
二叉搜索树(Search Binary Tree)
每一颗子树都满足,左子树上所有节点的值都小于根节点的值,右子树都大于
所以就能得到性质:左子树的值 < 根 < 右子树的值
它也称二叉排序树或二叉查找树,最多找高度次O(N)
二叉搜索树蜕化为单边树(或类似单边),其平均比较次数为:O(N)
搜索二叉树由于控制不了极端情况,与 O(logN) 失之交臂了,但后面讲到的平衡二叉搜索树可以做到。
template struct BSTreeNode {//全部都共有开放的,就直接定struct BSTreeNode* _left;//左结构体指针 BSTreeNode* _right; K _key; BSTreeNode(const K& key) :_left(nullptr) ,_right(nullptr) ,_key(key) {} }; //定义一个树 template class BATree{ typedef BSTreeNode Node; private: Node* _root = nullptr; // 这里我们构造函数都没必要写,它自己生成的就够用了 };
思路:
在我们更换 cur 结点时记录父结点的位置
parent=cur
即可。parent 意义:确认位置,实现插入
4.比较确定 cur 应该链接父亲的左边,还是链接父亲的右边,插入即可
//插入 bool Insert(const K& key) { //没有根节点就new一个 if (_root == nullptr) { _root = new Node(key); return true; } Node* parent = nullptr; Node* cur = _root; //循环比较 while (cur) { if (cur->_key < key) { parent = cur; cur = cur->_right;//小了就应该往右找 } else if(cur->_key > key) { parent = cur; cur = cur->_left; } else { return false; }//不断比较,搜索找到了之后 } //new了一个新节点,和parent的key比较,确定插入的左右 cur = new Node(key); if (parent->_key < key) { parent->_right = cur; } else { parent->_left = cur; }//将新节点插入到二叉树里面啦 return true; }
再写一个中序遍历来测试一下插入的效果:
void InOrder(Node* root) { if (root == nullptr) { return; } InOrder(root->_left); // 左 cout << root->_key << " "; // 值 InOrder(root->_right); // 右 } //测试 void TestBSTree() { BSTree t; int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 }; for (auto e : a) { t.Insert(e); } t.InOrder(); ❌ 没法传根 }
此时会出现一个问题,因为根是私有的,我们没办法把根传过去,我们可以采取 getroot,这里的话,我们将其设为内部函数即可
void InOrder() { _InOrder(_root); } private: // 改为内部函数 void _InOrder(Node* root) { if (root == nullptr) { return; } _InOrder(root->_left); cout << root->_key << " "; _InOrder(root->_right); } Node* _root = nullptr; };
完整测试代码:
#include using namespace std; template struct BSTreeNode { BSTreeNode* _left; BSTreeNode* _right; K _key; BSTreeNode(const K& key) : _left(nullptr) , _right(nullptr) , _key(key) {} }; template class BSTree { typedef BSTreeNode Node; public: BSTree() : _root(nullptr) {} bool Insert(const K& key) { if (_root == nullptr) { _root = new Node(key); return true; } Node* parent = nullptr; Node* cur = _root; //设置结构体形的cur节点,并进行初始化 while (cur) { if (cur->_key < key) { parent = cur; cur = cur->_right; } else if (cur->_key > key) { parent = cur; cur = cur->_left; } else { return false; // Key already exists } } cur = new Node(key); if (parent->_key < key) { parent->_right = cur; } else { parent->_left = cur; } return true; } void InOrder() { _InOrder(_root); cout << endl; } private: void _InOrder(Node* root) { if (root == nullptr) { return; } _InOrder(root->_left); cout << root->_key << " "; _InOrder(root->_right); } Node* _root; }; // 测试函数 void TestBSTree() { BSTree t; int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 }; for (auto e : a) { t.Insert(e); } t.InOrder(); } int main() { TestBSTree(); return 0; }
打印:
从根开始,如果要查找的值大于 cur 目前的值,则让 cur 往右走,反之往左走。
当查找得值与 cur 的值相等时则说明找到了,返回 true。
当 cur 触及到空(while 循环结束)则说明找不到,返回 false。
//查找 bool Find(const K& key) { Node* cur = _root;//从根开始 while (cur) {//循环查找 if (cur->_key < key) { cur = cur->_right; } else if (cur->_key > key) { cur = cur->_left; } else { return true; //找到啦 } } return false; //为空了还没找到就退出 }
搜索二叉树删除的实现是有难度的,删除的实现就需要一些技巧了,断然删除会毁树。
我们可以以下面这棵树为例
分别一次删除 7,14,3,8
7 和 14 属于直接删除的场景
3,8 属于需要替换法进行删除的场景
总结:
没有孩子,或者一个孩子都好删(直接删,托孤即可)
两个孩子以上就要采取替换法(左子树的最大节点,或者右子树的最小节点)
1.该结点无左孩子
画忘了,画成右为空了qwq,大家同理的理解一下
// 左为空 if (cur->_left == nullptr) { if (cur == _root) {//如果是根节点,parent就变为空了 _root = cur->_right; } else
if (cur->_left == nullptr) {//该结点无左孩子 /* 判断要删除的结点是否为根结点 */ if (cur == _root) { _root = cur->_right; } else { if (cur == father->_right) { //判断他是上一个节点的左节点还是右节点 father->_right = cur->_right; } else { father->_left = cur->_right; } } delete cur; cur = nullptr; }
左右都不为空--替换法
else { //查找到左边的最右节点 //右边的最左节点 //交换 //删除 // 找替代节点 Node* parent = cur; //不能设置为nullptr,循环可能不进去了 //之后要对父节点进行处理 Node* leftMax = cur->_left; //设置最大节点 while (leftMax->_right) { parent = leftMax; leftMax = leftMax->_right; //即最右节点 } //交换key swap(cur->_key, leftMax->_key);
删除的判断
//将parent置空处理,断联 if (parent->_left == leftMax) { parent->_left = leftMax->_left; } else { parent->_right = leftMax->_left; } //删除cur的处理 cur = leftMax; } delete cur; return true; } } return false;
#pragma once template struct BSTreeNode { BSTreeNode* _left; BSTreeNode* _right; K _key; BSTreeNode(const K& key) :_left(nullptr) ,_right(nullptr) ,_key(key) {} }; template class BSTree { typedef BSTreeNode Node; public: BSTree() :_root(nullptr) {} bool Insert(const K& key) { if (_root == nullptr) { _root = new Node(key); return true; } Node* parent = nullptr; Node* cur = _root; while (cur) { if (cur->_key < key) { parent = cur; cur = cur->_right; } else if(cur->_key > key) { parent = cur; cur = cur->_left; } else { return false; } } cur = new Node(key); if (parent->_key < key) { parent->_right = cur; } else { parent->_left = cur; } return true; } bool Find(const K& key) { Node* cur = _root; while (cur) { if (cur->_key < key) { cur = cur->_right; } else if (cur->_key > key) { cur = cur->_left; } else { return true; } } return false; } bool Erase(const K& key) { Node* parent = nullptr; Node* cur = _root; while (cur) { if (cur->_key < key) { parent = cur; cur = cur->_right; } else if (cur->_key > key) { parent = cur; cur = cur->_left; } else // 找到了 { // 左为空 if (cur->_left == nullptr) { if (cur == _root) { _root = cur->_right; } else { if (parent->_right == cur) { parent->_right = cur->_right; } else { parent->_left = cur->_right; } } }// 右为空 else if (cur->_right == nullptr) { if (cur == _root) { _root = cur->_left; } else { if (parent->_right == cur) { parent->_right = cur->_left; } else { parent->_left = cur->_left; } } } // 左右都不为空 else { // 找替代节点 Node* parent = cur; Node* leftMax = cur->_left; while (leftMax->_right) { parent = leftMax; leftMax = leftMax->_right; } swap(cur->_key, leftMax->_key); if (parent->_left == leftMax) { parent->_left = leftMax->_left; } else { parent->_right = leftMax->_left; } cur = leftMax; } delete cur; return true; } } return false; } void InOrder() { _InOrder(_root); cout << endl; } void _InOrder(Node* root) { if (root == NULL) { return; } //递归实现中序遍历的打印 _InOrder(root->_left); cout << root->_key << " "; _InOrder(root->_right); } private: Node* _root; };
测试:
void TestBSTree1() { int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 }; BSTree t; for (auto e : a) { t.Insert(e); } t.InOrder(); t.Erase(4); t.InOrder(); t.Erase(6); t.InOrder(); t.Erase(7); t.InOrder(); t.Erase(3); t.InOrder(); for (auto e : a) { t.Erase(e);//插入 } t.InOrder(); }
运行:
K 模型指的是只有 key 作为关键码的结构,在这种结构中只存储 key。K 模型常用于需要搜索具体值的场景,比如拼写检查、数字搜索等。
示例代码:K 模型的二叉搜索树
以下是一个实现 K 模型的二叉搜索树(BST)的完整代码示例:
#include using namespace std; template struct BSTreeNode { BSTreeNode* _left; BSTreeNode* _right; K _key; BSTreeNode(const K& key) : _left(nullptr) , _right(nullptr) , _key(key) {} }; template class BSTree { typedef BSTreeNode Node; public: BSTree() : _root(nullptr) {} bool Insert(const K& key) { if (_root == nullptr) { _root = new Node(key); return true; } Node* parent = nullptr; Node* cur = _root; while (cur) { if (cur->_key < key) { parent = cur; cur = cur->_right; } else if (cur->_key > key) { parent = cur; cur = cur->_left; } else { return false; // Key already exists } } cur = new Node(key); if (parent->_key < key) { parent->_right = cur; } else { parent->_left = cur; } return true; } void InOrder() { _InOrder(_root); cout << endl; } private: void _InOrder(Node* root) { if (root == nullptr) { return; } _InOrder(root->_left); cout << root->_key << " "; _InOrder(root->_right); } Node* _root; }; // 测试函数 void TestBSTree() { BSTree t; int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 }; for (auto e : a) { t.Insert(e); } t.InOrder(); } int main() { TestBSTree(); return 0; }
KV 模型表示每一个关键码 (key) 都有与之对应的值 (value),即
示例代码:KV 模型的二叉搜索树
以下是一个实现 KV 模型的二叉搜索树的完整代码示例:
#include #include using namespace std; template struct BSTreeNode { BSTreeNode* _left; BSTreeNode* _right; K _key; V _value; BSTreeNode(const K& key, const V& value) : _left(nullptr) , _right(nullptr) , _key(key) , _value(value) {} }; template class BSTree { typedef BSTreeNode Node; public: BSTree() : _root(nullptr) {} bool Insert(const K& key, const V& value) { if (_root == nullptr) { _root = new Node(key, value); return true; } Node* parent = nullptr; Node* cur = _root; while (cur) { if (cur->_key < key) { parent = cur; cur = cur->_right; } else if (cur->_key > key) { parent = cur; cur = cur->_left; } else { cur->_value = value; // Update value if key already exists return true; } } cur = new Node(key, value); if (parent->_key < key) { parent->_right = cur; } else { parent->_left = cur; } return true; } bool Find(const K& key, V& value) { Node* cur = _root; while (cur) { if (cur->_key < key) { cur = cur->_right; } else if (cur->_key > key) { cur = cur->_left; } else { value = cur->_value; return true; } } return false; } void InOrder() { _InOrder(_root); cout << endl; } private: void _InOrder(Node* root) { if (root == nullptr) { return; } _InOrder(root->_left); cout << "<" << root->_key << ", " << root->_value << "> "; _InOrder(root->_right); } Node* _root; }; // 测试函数 void TestKVTree() { BSTree dict; dict.Insert("apple", "苹果"); dict.Insert("banana", "香蕉"); dict.Insert("cherry", "樱桃"); string value; if (dict.Find("banana", value)) { cout << "banana: " << value << endl; } dict.InOrder(); } int main() { TestKVTree(); return 0; }
template struct BSTreeNode { BSTreeNode* _left; BSTreeNode* _right; K _key; V _value; BSTreeNode(const K& key, const V& value) : _left(nullptr) , _right(nullptr) , _key(key) , _value(value) {} };
template class BSTree { typedef BSTreeNode Node; public: BSTree() : _root(nullptr) {}
_root
以及插入、查找和中序遍历的方法。bool Insert(const K& key, const V& value) { if (_root == nullptr) { _root = new Node(key, value); return true; } Node* parent = nullptr; Node* cur = _root; while (cur) { if (cur->_key < key) { parent = cur; cur = cur->_right; } else if (cur->_key > key) { parent = cur; cur = cur->_left; } else { cur->_value = value; // Update value if key already exists return true; } } cur = new Node(key, value); if (parent->_key < key) { parent->_right = cur; } else { parent->_left = cur; } return true; }
bool Find(const K& key, V& value) { Node* cur = _root; while (cur) { if (cur->_key < key) { cur = cur->_right; } else if (cur->_key > key) { cur = cur->_left; } else { value = cur->_value; return true; } } return false; }
void InOrder() { _InOrder(_root); cout << endl; } private: void _InOrder(Node* root) { if (root == nullptr) { return; } _InOrder(root->_left); cout << "<" << root->_key << ", " << root->_value << "> "; _InOrder(root->_right); }
void TestKVTree() { BSTree dict; dict.Insert("apple", "苹果"); dict.Insert("banana", "香蕉"); dict.Insert("cherry", "樱桃"); string value; if (dict.Find("banana", value)) { cout << "banana: " << value << endl; } dict.InOrder(); } int main() { TestKVTree(); return