一.概念介绍
二叉搜索树,它如果不为空树,则它满足条件:1.左子树不为空,则左子树上的所有节点值小于根节点的值 2.右子树不为空,则右子树上所有节点值大于根节点的值 3.它的左右子树也分别为二叉搜索树。
如同就是一个标准的二叉搜索树:
二.对二叉搜索树代码的实现
-
key 搜索树模型 :对节点的创建
模板 K :表示的是所储存的值为K类型。
template<class K> struct BSTreeNode { BSTreeNode<K>* _left; BSTreeNode<K>* _right; K _key; // 对节点的创建 BSTreeNode(const K& key) :_left(nullptr) , _right(nullptr) , _key(key) {} };
对该模型其他功能的实现:
template<class K> class BSTree { //对 命名 的简化 typedef BSTreeNode<K> Node; public: // 创建新的节点,插入新的节点 bool Insert(K& e) { if (_root == nullptr) { _root = new Node(e); return true; } Node* cur = _root; while (cur) { if (cur->_key > e) { if (cur->_left) cur = cur->_left; else cur->_left = new Node(e), cur = nullptr; } else if (cur->_key < e) { if (cur->_right) cur = cur->_right; else cur->_right = new Node(e), cur = nullptr; } else { return false; } } return true; } // 删除key == e 的相关节点 细致讲解请看下面难点解析 bool Erase(const K& e) { Node* parent = nullptr; Node* cur = _root; while (cur) { if (cur->_key < e) { parent = cur; cur = cur->_right; } else if (cur->_key > e) { parent = cur; cur = cur->_left; } else { //删除 if (cur->_left == nullptr) { if (cur == _root) { _root = cur->_right; } else { if (cur == parent->_left) { parent->_left = cur->_right; } else { parent->_right = cur->_right; } } delete cur; } else if (cur->_right == nullptr) { if (cur == _root) { _root = cur->_left; } else { if (cur == parent->_left) { parent->_left = cur->_left; } else { parent->_right = cur->_left; } } delete cur; } else { Node* rightMinParent = cur; Node* rightMin = cur->_right; while (rightMin->_left) { rightMinParent = rightMin; rightMin = rightMin->_left; } swap(cur->_key, rightMin->_key); if (rightMinParent->_left == rightMin) rightMinParent->_left = rightMin->_right; else rightMinParent->_right = rightMin->_right; delete rightMin; } return true; } } return false; } //找到相关的值的节点 bool Find(const K& e) { Node* cur = _root; while (cur) { if (cur->_key < e) { cur = cur->_right; } else if (cur->_key > e) { cur = cur->_left; } else { return true; } } return false; } //中序遍历 void InOrder() { _InOrder(_root); } private: void _InOrder(Node* root) { if (root == nullptr) { return; } _InOrder(root->_left); cout << root->_key << " "; _InOrder(root->_right); } private: Node* _root = nullptr; }; // 附带的一组测试样例 void TestBSTree1() { int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 }; BSTree<int> t1; for (auto e : a) { t1.Insert(e); } t1.InOrder(); t1.Erase(3); cout << endl; t1.Erase(8); t1.InOrder(); for (auto e : a) { cout << endl; t1.Erase(e); t1.InOrder(); } }
三.二叉搜素树难点删除解析
四. key_value 的版本
与 key 的二叉搜素树基本类似,这里不做详细的说明:
仅仅不同的是有两个模板参数,K 与 V两个模板参数类型。
namespace key_value { //key 与 value 版本的 template<class K, class V> struct BSTreeNode { BSTreeNode<K, V>* _left; BSTreeNode<K, V>* _right; K _key; V _value; BSTreeNode(const K& key,const V& value) :_left(nullptr) ,_right(nullptr) ,_key(key) ,_value(value) {} }; template<class K,class V> class BSTree { typedef BSTreeNode<K, V> Node; public: bool Insert(const K& key, const V& value) { if (_root == nullptr) { _root = new Node(key,value); return true; } Node* cur = _root; while (cur) { if (cur->_key > key) { if (cur->_left) cur = cur->_left; else cur->_left = new Node(key,value), cur = nullptr; } else if (cur->_key < key) { if (cur->_right) cur = cur->_right; else cur->_right = new Node(key,value), cur = nullptr; } else { return false; } } return true; } Node* 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 cur; } } return cur; } bool Erase(const K& key) { Node* cur = _root; Node* parent = nullptr; while (cur) { if (cur->_key > key) { parent = cur; cur = cur->_left; } else if(cur->_key <key) { parent = cur; cur = cur->_right; } else { if (cur->_left == nullptr) { if (_root == cur) { _root = _root->_right; } else { if (cur == parent->_left) { parent->_left = cur->_right; } else { parent->_right = cur->_right; } } delete cur; } else if (cur->_right == nullptr) { if (_root == cur) { _root = _root->_left; } else { if (cur == parent->_left) { parent->_left = cur->_left; } else { parent->_right = cur->_left; } } delete cur; } else { Node* leftMax = cur->_left; Node* leftMaxP = cur; while (leftMax ->_right!= nullptr) { leftMaxP = leftMax; leftMax = leftMax->_right; } swap(cur->_key, leftMax->_key); swap(cur->_value, leftMax->_value); • if (leftMaxP->_right == leftMax) { leftMaxP->_right = leftMax->_left; } else { leftMaxP->_left = leftMax->_left; } delete leftMax; } 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 << endl; _InOrder(root->_right); } private: Node* _root = nullptr; }; void TestBSTree2() { BSTree<string, string> dict; dict.Insert("string", "字符串"); dict.Insert("left", "左边"); dict.Insert("insert", "插入"); string str; while (cin >> str) { BSTreeNode<string, string>* ret = dict.Find(str); if (ret) { cout << ret->_value << endl; } else { cout << "无此单词,请重新输入" << endl; } } } void TestBSTree3() { // 统计次数 string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉","苹果","草莓", "苹果","草莓" }; BSTree<string, int> countTree; for (const auto& str : arr) { auto ret = countTree.Find(str); if (ret == nullptr) { countTree.Insert(str, 1); } else { ret->_value++; } } countTree.InOrder(); } void TestBSTree4() { BSTree<string, string> dict; dict.Insert("string", "字符串"); dict.Insert("left", "左边"); dict.Insert("insert", "插入"); dict.Insert("hello", "你好"); dict.Insert("love", "爱你"); dict.Insert("rain", "雨"); dict.Insert("banana", "香蕉"); dict.Insert("ant", "蚂蚁"); dict.Insert("zabro", "斑马"); dict.Insert("yoyo", "悠悠球"); dict.InOrder(); dict.Erase("left"); dict.Erase("love"); dict.InOrder(); } }
五. 总结
二叉搜素树非常重要对于C++的学习来说,之后设计到的容器set 和 map 所依赖的基础都是 二叉搜索树,二叉搜素树的删除是相对难的重点,插入的时候是有去重操作的,对于插入重复的值是不能够成功插入的。希望大家能好好吸收这一章所讲述的内容,仔细研究代码,自己画图进行理解。