1. 二叉树搜索树的应用
- K模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。(确定一个值在不在)
比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:以词库中所有单词集合中的每个单词作为key,构建一棵二叉搜索树在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。 - KV模型:每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对。()
该种方式在现实生活中非常常见:
比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文<word, chinese>就构成一种键值对;
再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出现次数就是<word, count>就构成一种键值对。
改造二叉搜索树为KV结构
#pragma once #include <iostream> using namespace std; namespace KV { 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; Node* parent = nullptr; while (cur) { parent = cur; if (key > cur->_key) { cur = cur->_right; } else if (key < cur->_key) { cur = cur->_left; } else { return false; } } cur = new Node(key,value); if (key > parent->_key) { parent->_right = cur; } if (key < parent->_key) { parent->_left = cur; } return true; } //中序打印 void InOrder() { _InOrder(_root); cout << endl; } //查找 Node * Find(const K& key) { Node* cur = _root; while (cur) { if (key > cur->_key) { cur = cur->_right; } else if (key < cur->_key) { cur = cur->_left; } else { return cur; } } return nullptr; } //删除 bool Erase(const K& key) { Node* cur = _root; Node* parent = nullptr; while (cur) { if (key > cur->_key) { parent = cur; cur = cur->_right; } else if (key < cur->_key) { 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; } } 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; } } else {//左右都不为空 Node* SubLeft = cur->_right; Node* _parent = cur; while (SubLeft->_left) { _parent = SubLeft; SubLeft = SubLeft->_left; } swap(cur->_key, SubLeft->_key); if (SubLeft == _parent->_left) { _parent->_left = SubLeft->_right; } else { _parent->_right = SubLeft->_right; } } return true; } } return false; } 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; }; }
统计水果出现次数
int main() { string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜","苹果", "香蕉", "苹果", "香蕉" }; KV::BSTree<string, int> CountTree; for (auto &e : arr) { KV::BSTreeNode<string, int>* ret = CountTree.Find(e); if (ret == nullptr) { CountTree.Insert(e,1); } else { ret->_value++; } } CountTree.InOrder(); return 0; }
输入单词,查找单词对应的中文翻译
int main() { KV::BSTree<string, string> dict; dict.Insert("sort", "快排"); dict.Insert("left", "左边"); dict.Insert("right", "右边"); dict.Insert("insert", "插入"); dict.Insert("key", "键值"); string str; while (cin>>str) { KV::BSTreeNode<string, string>* ret = dict.Find(str); if (ret) { cout << ret->_value << endl; } else { cout << " 无此单词" << endl; } } return 0; }
2. 二叉搜索树的性能分析
插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。
对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树:
最优情况下,二叉搜索树为完全二叉树(或者接近完全二叉树),其平均比较次数为:l o g 2 N log_2 Nlog2N
最差情况下,二叉搜索树退化为单支树(或者类似单支),其平均比较次数为:N 2 \frac{N}{2}2N
3. 二叉树进阶面试题
这些题目更适合使用C++完成,难度也更大一些