二叉树进阶

Posted 在下赵某人

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树进阶相关的知识,希望对你有一定的参考价值。

目录:

1 二叉搜索树概念

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

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树
    eg:
    int a [] = 5,3,4,1,7,8,2,6,0,9

2 二叉搜索树操作

1. 二叉搜索树的查找

  • 普通数组链表:暴力查找 — O(N)
  • 排序数组:二分查找 — O(logN)
  • 二叉搜索树结构查找一个值,最多查找高度次
  • 二叉树中插入一个数,有唯一的位置。

2. 二叉搜索树的插入
插入的具体过程如下:

  • a. 树为空,则直接插入
  • b. 树不空,按二叉搜索树性质查找插入位置,插入新节点

3. 二叉搜索树的删除
首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情况:

  • a. 要删除的结点无孩子结点
  • b. 要删除的结点只有左孩子结点
  • c. 要删除的结点只有右孩子结点
  • d. 要删除的结点有左、右孩子结点
    看起来有待删除节点有4中情况,实际情况a可以与情况b或者c合并起来,因此真正的删除过程如下:
    情况b:删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点
    情况c:删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点
    情况d:在它的右子树中寻找最小值,用它的值填补到被删除节点中,再来处理该结点的删除问题。

3 二叉搜索树的实现

递归版实现:

namespace KEY

	template<class K>
	struct BSTNode
	
		//构造
		BSTNode(const K& key)
			: _left(nullptr)
			, _right(nullptr)
			, _key(key)
		

		BSTNode* _left;
		BSTNode* _right;
		K _key;
	;

	template<class K>
	class BSTreeR
	
		typedef BSTNode<K> Node;
	public:
		//构造
		BSTreeR()
			: _root(nullptr)
		
		//拷贝构造
		BSTreeR(BSTreeR& t)
		
			_root = Copy(t._root);
		
		//拷贝函数
		Node* Copy(Node* root)
		
			if (root == nullptr)
			
				return nullptr;
			
			//先new出一个节点
			Node* newRoot = new Node(root->_key);
			newRoot->_left = Copy(root->_left);
			newRoot->_right = Copy(root->_right);
			return newRoot;
		
		//赋值操作符重载
		BSTreeR<K>& operator=(BSTreeR<K> t)
		
			std::swap(this->_root, t->_root);
			return *this;
		
		//析构函数
		~BSTreeR()
		
			Destory(_root);
		
		void Destory(Node* root)
		
			if (root == nullptr)
			
				return;
			
			Destory(root->_left);
			Destory(root->_right);
			delete root;
		
		//插入函数
		bool Insert(const K& key)
		
			return _InsertR(_root, key);
		
		//中序遍历函数
		void InOrderR()
		
			_InOrderR(_root);
			cout << endl;
		
		//查找函数
		Node* Find(const K& key)
		
			return _FindR(_root, key);
		
		//删除函数
		bool Erase(const K& key)
		
			return _EraseR(_root, key);
		
	private:
		//递归版插入函数
		bool _InsertR(Node*& root, const K& key)
		
			if (root == nullptr)
			
				//插入
				root = new Node(key);
			
			else
			
				//查找
				if (key == root->_key)
				
					return false;
				
				else if (key > root->_key)
				
					return _InsertR(root->_right, key);//到右树去找
				
				else
				
					return _InsertR(root->_left, key);//到左树去找
				
			
			return true;
		
		//递归版中序遍历函数
		void _InOrderR(Node* root)
		
			if (root == nullptr)
			
				return;
			
			_InOrderR(root->_left);
			cout << root->_key << " ";
			_InOrderR(root->_right);
		
		//递归版查找函数
		Node* _FindR(Node* root, const K& key)
		
			if (root == nullptr)
			
				return nullptr;
			
			else
			
				if (root->_key == key)
				
					return root;
				
				else if (key < root->_key)
				
					return _FindR(root->_left, key);
				
				else
				
					return _FindR(root->_right, key);
				
			
		
		//递归版删除函数
		bool _EraseR(Node*& root, const K& key)
		
			//找不到key,或空树情况
			if (root == nullptr)
			
				return false;
			
			else
			
				//查找
				if (key > root->_key)
				
					_EraseR(root->_right, key);
				
				else if (key < root->_key)
				
					_EraseR(root->_left, key);
				
				else
				
					//提前记录要删除的位置
					Node* tmp = root;
					//找到了,开始删除
					if (root->_left == nullptr)
					
						//该节点左为空
						root = root->_right;
					
					else if (root->_right == nullptr)
					
						//该节点右为空
						root = root->_left;
					
					else
					
						//左右都不为空
						Node* minRight = root->_right;
						//在右树中找最小值,即右树中的最左值
						while (minRight->_left)
						
							minRight = minRight->_left;
						
						//将要删除的值用右树中的最左值替代
						root->_key = minRight->_key;
						//删除右树中的最左值
						return _EraseR(root->_right, minRight->_key);
					
					//释放删除节点的空间
					delete tmp;
				
				return true;
			
		
		Node* _root = nullptr;
	;

void test_BSTree_R()

	KEY::BSTreeR<int> t1;
	int a[] =  5,3,4,1,7,8,2,6,0,9 ;
	cout << "t1:";
	for (auto e : a)
	
		t1.Insert(e);
	
	t1.InOrderR();

	KEY::BSTreeR<int> t2 = t1;
	cout << "t2:";
	t2.InOrderR();

	KEY::BSTreeR<int> t(t1);
	cout << "t :";
	t.InOrderR();
	KEY::BSTNode<int>* F;
	F = t.Find(3);
	F = t.Find(5);
	F = t.Find(7);
	F = t.Find(1);
	for (auto e : a)
	
		t.Erase(e);
		t.InOrderR();
	
	cout << "程序结束" << endl;


int main()

	//KEY模型测试
	test_BSTree_R();
	return 0;

4 二叉搜索树的应用

1. K模型

K模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。
比如:给一个单词word,判断该单词是否拼写正确,
具体方式如下:以单词集合中的每个单词作为key,构建一棵二叉搜索树,在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。
附:K模型即上面的搜索二叉树模型

2. KV模型

KV模型:每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对。
比如:

  • 英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文<word, chinese>就构成一种键值对;
  • 统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出现次数就是<word, count>就构成一种键值对。

eg:
实现一个简单的英汉词典dict可以通过英文找到与其对应的中文,具体实现方式如下:

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

	template<class K, class V>
	struct BSTNode
	
		//构造
		BSTNode(const K& key, const V& value)
			: _left(nullptr)
			, _right(nullptr)
			, _key(key)
			, _value(value)
		

		BSTNode* _left;
		BSTNode* _right;
		K _key;
		V _value;
	;

	template<class K,class V>
	class BSTreeR
	
		typedef BSTNode<K, V> Node;
	public:
		//构造
		BSTreeR()
			: _root(nullptr)
		
		//拷贝构造
		BSTreeR(BSTreeR& t)
		
			_root = Copy(t._root);
		
		//拷贝函数
		Node* Copy(Node* root)
		
			if (root == nullptr)
			
				return nullptr;
			
			//先new出一个节点
			Node* newRoot = new Node(root->_key, root->_value);
			newRoot->_left = Copy(root->_left);
			newRoot->_right = Copy(root->_right);
			return newRoot;
		
		//赋值操作符重载
		BSTreeR<K, V>& operator=(BSTreeR<K, V> t)
		
			std::swap(this->_root, t->_root);
			return *this;
		
		//析构函数
		~BSTreeR()
		
			Destory(_root);
		
		void Destory(Node* root)
		
			if (root == nullptr)
			
				return;
			
			Destory(root->_left);
			Destory(root->_right);
			delete root;
		
		//插入函数
		bool Insert(const K& key, const V& value)
		
			return _InsertR(_root, key, value);
		
		//中序遍历函数
		void InOrderR()
		
			_InOrderR(_root);
			cout << endl;
		
		//查找函数
		Node* Find(const K& key)
		
			return _FindR(_root, key);
		
		//删除函数
		bool Erase(const K& key)
		
			return _EraseR(_root, key);
		
	private:
		//递归版插入函数
		bool _InsertR(Node*& root, const K& key, const V& value)
		
			if (root == nullptr)
			
				//插入
				root = new Node(key, value);
			
			else
			
				//查找
				if (key == root->_key)
				
					return false;
				
				else if (key > root->_key)
				
					return _InsertR(root->_right, key ,value);//到右树去找
				
				else
				
					return _InsertR(root->_left, key , value);//到左树去找
				
			
			return true;
		
		//递归版中序遍历函数
		void _InOrderR(Node* root)
		
			if (root == nullptr)
			
				return;
			
			_InOrderR(root->_left);
			cout << root->_key << root->_value << " ";
			_InOrderR(root->_right);
		
		//递归版查找函数
		Node* _FindR(Node* root, const K& key)
		
			if (root == nullptr)
			
				return nullptr;
			
			else
			
				if (root->_key == key)
				
					return root;
				
				else if (key < root->_key)
				
					return _FindR(root->_left, key);
				
				else
				
					return _FindR(root->_right, key);
				
			
		
		//递归版删除函数
		bool _EraseR(Node*& root, const K& key)
		
			//找不到key,或空树情况
			if (root == nullptr)
			
				return false;
			
			else
			
				//查找
				if (key > root->_key)
				
					_EraseR(root->_right, key);
				
				else if (key < root->_key)
				
					_EraseR(root->_left, key);
				
				else
				
					//提前记录要删除的位置
					Node* tmp = root;
					//找到了,开始删除
					if (root->_left == nullptr)
					
						//该节点左为空
						root = root->_right;
					
					else if (root->_right == nullptr)
					
						//该节点右为空
						root = root->_left;
					
					else
					
						//左右都不为空
						Node* minRight = root->_right;
						//在右树中找最小值,即右树中的最左值
						while (minRight->_left)
						
							minRight = minRight->_left;
						
						//将要删除的值用右树中的最左值替代
						root->_key = minRight->_key;
						//删除右树中的最左值
						return _EraseR(root->_right, minRight->_key);
					
					//释放删除节点的空间
					delete tmp;
				
				return true;
			
		
		Node* _root = nullptr;
	;

void test_K_Value_R()

	KEY_VALUE::BSTreeR<string,string> t1;
	t1.Insert("world", "单词");
	t1.Insert("sort", "删除");
	t1.Insert("left", "单词");
	t1.Insert("right", "单词");
	cout << "t1:";
	t1.InOrderR();

	KEY_VALUE::BSTreeR<string, string> t2 = t1;
	cout << "t2:";
	t2.InOrderR();

	KEY_VALUE::BSTreeR<string, string> t3(t1);
	cout << "t3:";
	t3.InOrderR();

	cout << "程序结束" << endl;


void COUT_CHINESE()

	KEY_VALUE::BSTreeR<string, string数据结构二叉树

软考笔记(数据结构篇)———— 二叉树树森林转换

左神算法进阶班5_1求二叉树中最大搜索子树大小

二叉树的定义

二叉树进阶之寻找一棵二叉树中的最大二叉搜索子树

常用数据结构——二叉树(还有三叉四叉...? )