二叉树的进阶——C++ 二叉搜索树

二叉搜索树

  • 一、二叉搜索树
    • 1.二叉搜索树的概念
    • 2.二叉搜索树的使用场景
  • 二、二叉搜索树的分类
    • 1.Key树
      • 模拟实现key树
    • 2.KV树
      • 模拟实现KV树

一、二叉搜索树

1.二叉搜索树的概念

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:

  1. 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  2. 若它的右子树不为空,则右子树所有的节点都大于根节点的值
  3. 它的左右子树也是二叉搜索树
    二叉树的进阶——C++ 二叉搜索树_第1张图片

2.二叉搜索树的使用场景

因为二叉搜索树的性质,它的中序是有序的。所以可以用来进行排序(用的不多)
既然叫做二叉搜索树,那么主要用来搜索。在一般情况下,二叉搜索树的时间复杂度趋近于O(logn),但是,如果是单支树(只有左子树或者只有右子树)那么时间复杂度就回到了O(n)。

二、二叉搜索树的分类

1.Key树

K模型:K模型即只有key作为关键码,结构中只需要存储key即可,关键码即为需要搜素到的值。
比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:

  1. 以单词集合中的每个单词作为key,构建一棵二叉搜索树
  2. 在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误

模拟实现key树

二叉搜索树的删除
首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情况:
a. 要删除的结点无孩子结点
b. 要删除的结点只有左孩子结点
c. 要删除的结点只有右孩子结点
d. 要删除的结点有左、右孩子结点
看起来有待删除节点有4中情况,实际情况a可以与情况b或者c合并起来,因此真正的删除过程如下:

  1. 情况b:删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点
  2. 情况c:删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点
  3. 情况d:在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,再来处理该结点的删除问题
#pragma once
#include
using namespace std;

template<class K>
struct  BSTreeNode
{
	K _key;
	struct BSTreeNode<K>* _left;
	struct BSTreeNode<K>* _right;

	BSTreeNode(const K& key)
		:_key(key)
		, _left(nullptr)
		, _right(nullptr)
	{}
};

template<class K>
class BSTree
{
	typedef BSTreeNode<K> Node;
public:
	bool Insert(const K& key)
	{
		if (_root == nullptr) {
			_root = new Node(key);
			return true;
		}

		Node* cur = _root;
		Node* pre = nullptr;
		while (cur) {
			if (cur->_key > key) {
				pre = cur;
				cur = cur->_left;
			}
			else if (cur->_key < key) {
				pre = cur;
				cur = cur->_right;
			}
			else
				return false;
		}
		Node* newnode = new Node(key);
		if (pre->_key > key) {
			pre->_left = newnode;
		}
		else {
			pre->_right = newnode;
		}
		return true;
	}
	bool Erase(const K& key)
	{
		Node* pre = nullptr;
		Node* cur = _root;
		while (cur) {
			if (cur->_key < key) {
				pre = cur;
				cur = cur->_right;
			}
			else if (cur->_key > key) {
				pre = cur;
				cur = cur->_left;
			}
			else {
				//准备删除
				//1.左为空
				//2.右为空
				//3.左右都不为空
				if (cur->_left == nullptr) {
					//特殊情况:cur同时是根,pre是nullptr
					if (cur == _root) {
						_root = cur->cur;
					}
					else {
						if (cur == pre->_left) {
							pre->_left = cur->_right;
						}
						else {
							pre->_right = cur->_right;
						}
					}
					delete cur;
				}
				else if (cur->_right == nullptr) {
					if (cur == _root) {
						_root = cur->_left;
					}
					else {
						if (cur == pre->_left) {
							pre->_left = cur->_left;
						}
						else {
							pre->_right = cur->_left;
						}
					}
					delete cur;
				}
				else {
					//替代法删除
					//右树的最小节点(最左节点)
					//要注意的特殊情况是右子树根有可能就是最小节点
					Node* smpre = cur;
					Node* subMin = cur->_right;
					while (subMin->_left) {
						smpre = subMin;
						subMin = subMin->_left;
					}
					cur->_key = subMin->_key;
					//subMin一定是一个左为空的节点
					if (smpre->_left == subMin) {
						smpre->_left = subMin->_right;
					}
					else {
						smpre->_right = subMin->_right;
					}
					delete subMin;
				}

				return true;
			}
		}
		return false;
	}
	void _InOrder(Node* root)
	{
		if (root == nullptr)
			return;
		_InOrder(root->_left);
		cout << root->_key << " ";
		_InOrder(root->_right);
	}
	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}
	const 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;
	}
private:
	Node* _root = nullptr;
};

2.KV树

KV模型:每一个关键码key,都有与之对应的val,即的键值对。 该种方式在现实生活中非常常见:比如英汉字典就是英文与中文的对应关系,通过英文可以快速找到对应的中文;再比如统计单词个数,统计成功后,给定单词就可快速找到其中出现的次数。
比如:实现一个简单的英汉词典dict,可以通过英文找到对应中文,具体方式如下:

  1. <单词,中文含义>为键值对构造二叉搜索树,注意:二叉搜索树需要比较,键值对比较时只比较key
  2. 查询英文单词时,只需给出英文单词,就可以快速找到与其对应的key

模拟实现KV树

#pragma once
#include
using namespace std;

template<class K,class V>
struct  BSTreeNode
{
	const K _key;
	V _val;
	struct BSTreeNode<K,V>* _left;
	struct BSTreeNode<K,V>* _right;

	BSTreeNode(const K& key,const V& val)
		:_key(key)
		,_val(val)
		, _left(nullptr)
		, _right(nullptr)
	{}
};

template<class K,class V>
class BSTree
{
	typedef BSTreeNode<K,V> Node;
public:
	bool Insert(const K& key,const V& val)
	{
		if (_root == nullptr) {
			_root = new Node(key,val);
			return true;
		}

		Node* cur = _root;
		Node* pre = nullptr;
		while (cur) {
			if (cur->_key > key) {
				pre = cur;
				cur = cur->_left;
			}
			else if (cur->_key < key) {
				pre = cur;
				cur = cur->_right;
			}
			else
				return false;
		}
		Node* newnode = new Node(key,val);
		if (pre->_key > key) {
			pre->_left = newnode;
		}
		else {
			pre->_right = newnode;
		}
		return true;
	}
	void _InOrder(Node* root)
	{
		if (root == nullptr)
			return;
		_InOrder(root->_left);
		cout << root->_key << ":" << root->_val << endl;
		_InOrder(root->_right);
	}
	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}
	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;
	}
private:
	Node* _root = nullptr;
};

你可能感兴趣的:(二叉树)