赞
踩
目录
二叉搜索树(BST, Binary Search Tree),也称为二叉排序树或二叉查找树。
每一棵搜索树都满足如下条件:
1.非空左子树的所有键值小于其根节点的键值
2.非空右子树的所有键值大于其根节点的键值
3.左、右子树都是二叉搜索树
如图所示二叉树:
如该树 数组表示为:int a[] = {8, 3, 1, 10, 6, 4, 7, 14, 13}; 用此树进行讲解
下面代码用到的c++类结构为:
- template<class K> //模板
- struct BSTreeNode {
- BSTreeNode<K>* _left;
- BSTreeNode<K>* _right;
- K _key;
- private:
- Node* _root = nullptr;
- };
a、从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。
b、最多查找高度次,走到到空,还没找到,这个值不存在。
代码实现:
非递归:
- bool Find(const K& key) //K为模板
- {
- 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 _FindR(Node* root, const K& key)
- {
- if (root == nullptr)
- return false;
-
- if (root->_key < key)
- return _FinfR(root->_right, key);
- else if (root->_key > key)
- return _FindR(root->_left, key);
- else
- return true;
- }
插入的具体过程如下:
a. 树为空,则直接新增节点,赋值给root指针
b. 树不空,按二叉搜索树性质查找插入位置,插入新节点(大于根节点值往右走,小于根节点值往左走)。注意:二叉搜索树插入过程中,插入已存在值无意义。
为该树插入16 、9 两个值,根据搜素树应满足的“左小右大”的条件,插入后如图:
代码实现:
非递归写法:
- bool Insert(const K& key) //K为模板
- {
- //空树直接插
- 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 _InsertR(Node*& root, const K& key) //K为模板
- {
- if (root == nullptr)
- {
- root = new Node(key);
- return true;
- }
-
- if (root->_key < key)
- {
- return _InsertR(root->_right, key);
- }
- else if (root->_key > key)
- {
- return _InsertR(root->_left, key);
- }
- else
- {
- return false;
- }
- }
删除某一节点可分为四种情况:
a.要删除节点没有孩子节点
如图删除节点值13,没有孩子节点,删除后父节点parent->left就指向空。
b.要删除的结点只有左孩子结点
c. 要删除的结点只有右孩子结点
该两种情况相似。如删除节点14后,其孩子节点13的父节点就变为10,即:10->right=13
d. 要删除的结点有左、右孩子结点
该情况难点在于删除节点后,被删除节点的父节点应该链接被删除节点的哪个孩子节点。这分为两种方法:
1.连接删除节点的左子树中最右边节点
2.连接删除节点的右子树中最左节点
一般情况下,我们使用方法2.在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,再来处理该结点的删除问题--替换法删除
代码实现:
非递归:
- 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
- {
- //找到当前位置后且左空,且位于parent的左,
- //则删除该位置后的parent左就变为cur的右
- //如果当前位置位于parren右,且且左空,则paret的右即为cur的右
- if (cur == parent->_left)
- {
- parent->_left = cur->_right;
- }
- else
- {
- parent->_right = cur->_right;
- }
- }
- delete cur;
- cur == nullptr;
- }
- 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;
- cur = nullptr;
- }
- else//左右都不为空
- {
- //替换法删除 //右子树最小节点---右子树最左节点
- Node* minparent = cur;
- Node* min = cur->_right;
- while (min->_left)
- {
- minparent = min;
- min = min->_left;
- }
- swap(cur->_key, min->_key);
- if (minparent->_left == min)
- minparent->_left = min->_right;
- else
- minparent->_right = min->_right;
- delete min;
- }
- return true;
- }
- }
- return false;
- }
递归:
- bool _EraseR(Node*& root, const K& key)
- {
- if (root == nullptr)
- {
- return false;
- }
-
- if (root->_key < key)
- {
- return _EraseR(root->_right, key);
- }
- else if (root->_key > key)
- {
- return _EraseR(root->_left, key);
- }
- else
- {
- Node* del = root;
- if (root->_left == nullptr)
- {
- root = root->_right;
- }
- else if (root->_right == nullptr)
- {
- root = root->_left;
- }
- else
- {
- //找右数的最左节点
- Node* min = root->_right;
- while (min->_left)
- {
- min = min->_left;
- }
- swap(root->_key, min->_key);
- return _EraseR(root->_right, key);
- }
-
- delete del;
- return true;
- }
- }
这里可以将创建的二叉搜索树通过中序(左->根->右)打印出来,就是由小到大的升序序列。因为二叉搜索树中不能有重复的数值,所以可以通过插入一组数据实现对其排序且去重。
- void _InOrder(Node* root)
- {
- if (root == nullptr)
- {
- return;
- }
- _InOrder(root->_left);
- cout << root->_key << " ";
- _InOrder(root->_right);
-
- }
该二叉搜索树的整体代码放在文末。
上面我们所实现的就是K模型。
K模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到
的值。
比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:
以词库中所有单词集合中的每个单词作为key,构建一棵二叉搜索树,在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误
KV模型:每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对。一般可以通过查找关键码key来查找对应的值。
比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英
文单词与其对应的中文<word, chinese>就构成一种键值对。(KV模型整体代码与K模型思想很相似,就直接放在文末)
- void TestBSTree1()
- {
- BSTree<string, string> dict;
- dict.Insert("sort", "排序");
- dict.Insert("left", "左边");
- dict.Insert("right", "右边");
- dict.Insert("string", "字符串");
- dict.Insert("insert", "插入");
- string str;
- while (cin >> str)
- {
- BSTreeNode<string, string>* ret = dict.Find(str);
- if (ret)
- {
- cout << ":" << ret->_value << endl;
- }
- else
- {
- cout << "->无此单词" << endl;
- }
- }
- }
再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出
现次数就是<word, count>就构成一种键值对。
- void TestBSTree2()
- {
- string arr[] = { "苹果","苹果" ,"香蕉" ,"草莓" ,"香蕉" ,"苹果" ,"苹果", "苹果" };
-
- BSTree<string, int> countTree;
- for (auto& str:arr)
- {
- auto ret = countTree.Find(str);
- if (ret)
- {
- ret->_value++;
- }
- else
- {
- countTree.Insert(str, 1);
- }
- }
-
- countTree.InOrder();
- }
- namespace key
- {
- template<class K>
- struct BSTreeNode {
- BSTreeNode<K>* _left;
- BSTreeNode<K>* _right;
- K _key;
-
- BSTreeNode(const K& key)
- :_left(nullptr)
- , _right(nullptr)
- , _key(key)
- {}
- };
-
-
- //BinarySearchTree
- template<class K> //Key
- class BSTree {
- typedef BSTreeNode<K> Node;
- public:
- 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
- {
- //找到当前位置后且左空,且位于parent的左,
- //则删除该位置后的parent左就变为cur的右
- //如果当前位置位于parren右,且且左空,则paret的右即为cur的右
- if (cur == parent->_left)
- {
- parent->_left = cur->_right;
- }
- else
- {
- parent->_right = cur->_right;
- }
- }
- delete cur;
- cur == nullptr;
- }
- 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;
- cur = nullptr;
- }
- else//左右都不为空
- {
- //替换法删除 //右子树最小节点---右子树最左节点
- Node* minparent = cur;
- Node* min = cur->_right;
- while (min->_left)
- {
- minparent = min;
- min = min->_left;
- }
- swap(cur->_key, min->_key);
- if (minparent->_left == min)
- minparent->_left = min->_right;
- else
- minparent->_right = min->_right;
- delete min;
- }
- return true;
- }
- }
- return false;
- }
-
- void InOrder()
- {
- _InOrder(_root);//这里套一层就可以直接使用_root;或者也可以写getroot方法
- cout << endl;
- }
-
- //递归查找
- bool FindR(const K& key)
- {
- return _FindR(_root, key);
- }
- //递归插
- bool InsertR(const K& key)
- {
- return _InsertR(_root, key);
- }
- //递归删
- bool EraseR(const K& key)
- {
- return _EraseR(_root, key);
- }
-
- ~BSTree()
- {
- _Destroy(_root);
- }
- //强制编译器生成默认的构造
- BSTree() = default;
- BSTree(const BSTree<K>& t)
- {
- _root = _copy(t._root);
- }
-
- BSTree<K>& operator=(BSTree<K> t)
- {
- swap(_root, t._root);
- return *this;
- }
- private:
- Node* _copy(Node* root)
- {
- if (root == nullptr)
- {
- return nullptr;
- }
- Node* copyRoot = new Node(root->_key);
- copyRoot->_left = _copy(root->_left);
- copyRoot->_right = _copy(root->_right);
- return copyRoot;
- }
- void _Destroy(Node*& root)
- {
- if (root == nullptr)
- {
- return;
- }
- _Destroy(root->_left);
- _Destroy(root->_right);
- delete root;
- root = nullptr;
- }
- bool _EraseR(Node*& root, const K& key)
- {
- if (root == nullptr)
- {
- return false;
- }
-
- if (root->_key < key)
- {
- return _EraseR(root->_right, key);
- }
- else if (root->_key > key)
- {
- return _EraseR(root->_left, key);
- }
- else
- {
- Node* del = root;
- if (root->_left == nullptr)
- {
- root = root->_right;
- }
- else if (root->_right == nullptr)
- {
- root = root->_left;
- }
- else
- {
- //找右数的最左节点
- Node* min = root->_right;
- while (min->_left)
- {
- min = min->_left;
- }
- swap(root->_key, min->_key);
- return _EraseR(root->_right, key);//很巧妙
- }
-
- delete del;
- return true;
- }
- }
- bool _InsertR(Node*& root, const K& key)
- {
- if (root == nullptr)
- {
- root = new Node(key);
- return true;
- }
-
- if (root->_key < key)
- {
- return _InsertR(root->_right, key);
- }
- else if (root->_key > key)
- {
- return _InsertR(root->_left, key);
- }
- else
- {
- return false;
- }
- }
- bool _FindR(Node* root, const K& key)
- {
- if (root == nullptr)
- return false;
-
- if (root->_key < key)
- return _FinfR(root->_right, key);
- else if (root->_key > key)
- return _FindR(root->_left, key);
- else
- return true;
- }
- //中序 //
- void _InOrder(Node* root)
- {
- if (root == nullptr)
- {
- return;
- }
- _InOrder(root->_left);
- cout << root->_key << " ";
- _InOrder(root->_right);
-
- }
- private:
- Node* _root = nullptr;
- };
- }
- 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* 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,value);
- if (parent->_key < key)
- {
- parent->_right = cur;
- }
- else
- {
- parent->_left = cur;
- }
- 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 nullptr;
- }
-
- 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
- {
- //找到当前位置后且左空,且位于parent的左,
- //则删除该位置后的parent左就变为cur的右
- //如果当前位置位于parren右,且且左空,则paret的右即为cur的右
- if (cur == parent->_left)
- {
- parent->_left = cur->_right;
- }
- else
- {
- parent->_right = cur->_right;
- }
- }
- delete cur;
- cur == nullptr;
- }
- 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;
- cur = nullptr;
- }
- else//左右都不为空
- {
- //替换法删除 //右子树最小节点---右子树最左节点
- Node* minparent = cur;
- Node* min = cur->_right;
- while (min->_left)
- {
- minparent = min;
- min = min->_left;
- }
- swap(cur->_key, min->_key);
- if (minparent->_left == min)
- minparent->_left = min->_right;
- else
- minparent->_right = min->_right;
- delete min;
- }
- return true;
- }
- }
-
- //删除的中间过程都一样
- return true;
- }
-
- void InOrder()
- {
- _InOrder(_root);//这里套一层就可以直接使用_root;或者也可以写getroot方法
- cout << endl;
- }
-
- private:
- //中序 //
- void _InOrder(Node* root)
- {
- if (root == nullptr)
- {
- return;
- }
- _InOrder(root->_left);
- cout << root->_key << " value: " << root->_value << endl;;
- _InOrder(root->_right);
-
- }
- private:
- Node* _root = nullptr;
- };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。