搜索二叉树【C++】

这篇具有很好参考价值的文章主要介绍了搜索二叉树【C++】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

二叉搜索树

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

若它的左子树不为空,
则左子树上所有结点的值都小于根结点的值。

若它的右子树不为空,
则右子树上所有结点的值都大于根结点的值。

它的左右子树也分别是二叉搜索树。

搜索二叉树【C++】,c++,java,数据结构

二叉搜索树的模拟实现

构造函数

	BSTree()
		:_root(nullptr)
	{

	}

拷贝构造函数

	BSTree(const  BSTree<K>& t)
			//BSTree(  BSTree<K>  *this ,  const  BSTree<K> & t)
			//t1 =t 
		{
			_root = Copy(t._root);
		}
		
			private:
		Node* Copy(Node* root)
		{
			if (root == nullptr)
			{
				return nullptr;
			}
			Node* copyNode = new Node(root->_key);
			//递归 
			copyNode->_left = Copy(root->_left);
			copyNode->_right = Copy(root->_right);
			return  copyNode;

		}

赋值运算符重载函数

	//赋值重载 
		BSTree<K>& operator= (BSTree<K>& t)
			//t1 = t
			//深拷贝
		{
			swap(_root, t._root);
			return *this;
		}

析构函数

~BSTree()
		{
			Destroy(_root);
		}
		
		private:
				void Destroy(Node*& root) //引用的目的:将每个节点释放后同时置空
		{
			//后序遍历 
			if (root == nullptr)
			{
				return;
			}
			Destroy(root->_left);
			Destroy(root->_right);
			delete root;
			root = nullptr;
		}

Insert

核心思路:

如果是空树,则直接将插入结点作为二叉搜索树的根结点。

如果不是空树,则按照二叉搜索树的性质进行结点的插入。
如果待插入结点的值<根结点的值,则需要将结点插入到左子树当中。
如果待插入结点的值>根结点的值,则需要将结点插入到右子树当中。
如果待插入结点的值等于根结点的值,则插入失败。

循环

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);
			
		
			//不知道parent在那一边,需要进一步判断
			if (parent->_key > key)
			{
				//parent在左边
				parent->_left = cur;
			}
			else if (parent->_key < key)
			{
				//parent在右边
				parent->_right = cur;

			}
			else
			{
				return false;
			}
		

		return true;
	}

递归

	bool InsertR(const K& key)//递归版本
		{
			return _InsertR(_root, key);
		}
		private:
			bool _InsertR(Node*& root, const K& key) //引用的目的:不用找父节点,不需要用父节点比较大小
		{
			//结束条件
			if (root == nullptr)
			{
				root = new Node(key);
				return true;
			}
			//往左子树走
			if (root->_key > key)
			{
				return _InsertR(root->_left, key);
			}
			//往右子树走
			else if (root->_key < key)
			{
				return _InsertR(root->_right, key);

			}
			else
			{
				return false;
			}
		}

Erase

先找到需要删除的节点
需要删除的节点可能会有三种情况:
1、待删除结点的左子树为空(待删除结点的左右子树均为空包含在内)

搜索二叉树【C++】,c++,java,数据结构

2、待删除结点的右子树为空。
搜索二叉树【C++】,c++,java,数据结构

1、2 两种情况,被删除的节点都只有一个孩子

3、待删除结点的左右子树均不为空,即被删除节点有两个孩子
使用替换法处理第3中情况:
1、找替换节点:替换节点一般是左子树的最大节点(最右节点),或者是右子树的最小节点(最左节点)
2、将替换的节点删除

搜索二叉树【C++】,c++,java,数据结构
特殊情况:

搜索二叉树【C++】,c++,java,数据结构

循环

	bool Erase(const K& key)
	{
		Node* parent = nullptr;//待删除节点的父节点
		Node* cur = _root;//待删除的节点

		//不是空树
		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 (cur == _root)
					{
						//将根节点改为待删除节点的右孩子
						_root = cur->_right;
					}
					//待删除节点不是根节点,并且此时parent不为nullptr
					else
					{
						if (parent->_right == cur)
						{
							parent->_right = cur->_right;
						}
						else//parent->_left ==cur
						{
							parent->_left = cur->_right;
						}
					}
					
				}
				//待删除节点的右子树为空 ,即一个孩子的情况
				else if (cur->_right == nullptr)
				{
					//待删除节点是根节点
					if (cur == _root)
					{
						//将根节点改为待删除节点的左孩子
						_root = cur->_left;
					}
					//待删除节点不是根节点,并且此时parent不为nullptr
					else
					{
						if (parent->_right == cur)
						{
							parent->_right = cur->_left;
						}
						else//parent->_left==cur
						{
							parent->_left = cur->_left;
						}
					}
				} 

				else //待删除的节点的左右孩子都不为空 (替换法:左子树的最大节点即最右节点,或者右子树的最小节点即最左节点,并且将替换的节点删除)
				{
					//替换法

					//找替代节点
					Node* parent = cur;
					//找左子树的最大节点,左子树的最大节点一定没有右孩子
					Node* leftMax = cur->_left;
					
					while (leftMax->_right)
					{
						parent = leftMax; //记录leftMax的父节点,防止删除leftMax时找不到该节点位置 
						//一直往右子树找
						leftMax = leftMax->_right;
					}
					//左子树的最大节点和待删除节点替换
					swap(cur->_key, leftMax->_key);
					//重新改变链接关系
					 
					//特殊情况 
					if (parent->_left == leftMax)
					{
						parent->_left = leftMax->_left;
					}
					else//普通情况 parent->_right== leftMax
					{
						parent->_right = leftMax->_left;
						
					}
					cur = leftMax;
				}
				//删除左子树的最大节点
				delete cur;
				return true;
			}
			
		}
		return false;
	}

递归

	bool EraseR(Node* _root, const K& key)//递归版本
		{
			return _EraseR(_root, key);
		}
		private:
				bool _EraseR(Node*& root, const K& key)//引用的目的:不用找父节点,不需要用父节点比较大小
		{
			//结束条件
			if (root == nullptr)
			{
				return false;
			}
			//往左树找
			if (root->_key > key)
			{
				return _EraseR(root->_left, key);
			}
			//往右树找
			else if (root->_key < key)
			{
				return _EraseR(root->_right, key);
			}
			else//找到,开始删除
			{
				Node* del = root;
				//待删除节点的左子树为空 ,即一个孩子的情况
				if (root->_left == nullptr)
				{
					root = root->_right;
				}
				//待删除节点的右子树为空 ,即一个孩子的情况
				else if (root->_right == nullptr)
				{
					root = root->_left;
				}
				//待删除的节点的左右孩子都不为空 (替换法:左子树的最大节点即最右节点,或者右子树的最小节点即最左节点,并且将替换的节点删除)
				else
				{
					//找左子树最大节点
					Node* leftMax = root->_left;
					//一直往左边找,直到找到左子树最大节点
					while (root->_left)
					{
						root = root->_left;
					}
					//将左子树最大节点与被删除节点替换
					swap(leftMax->_key, root->_key);

					return _EraseR(root, key);
				}

				delete del;//?
				return true;

			}


		}

Find

循环

	bool Find(const K & key)
	{
		Node* cur = _root;
		while (cur)
		{
			if (cur->_left > key)
			{
				cur = cur->_left;
			}
			else if (cur->_left < key)
			{
				cur = cur->_right;
			}
			else
			{
				return false;
			}
			return true;
		}
	}

递归

	bool FindR(Node* _root, const K& key)//递归版本
		{
			return _FindR(_root, key);
		}
		private:
		bool  _FindR(Node* root, const K& key)
		{
			//结束条件
			if (root == nullptr)
			{
				return false;
			}

			if (root->_key > key)
			{
				return _FindR(root->_left, key);
			}
			else if (root->_key < key)
			{
				return _FindR(root->_right, key);
			}
			else
			{
				return true;
			}
		}

二叉搜索树的应用

K模型

K模型,即只有key作为关键码,结构中只需存储key即可,关键码即为需要搜索到的值。

比如:给定一个单词,判断该单词是否拼写正确。具体方式如下:

	void TestBSTree1()
	{
		BSTree<string, string > dict;
		dict.InsertR("insert", "插入");
		dict.InsertR("sort", "排序");
		dict.InsertR("right", "右边");
		dict.InsertR("date", "日期");
		
		string str;
		while (cin>>str)
		{
			
			auto * ret  = dict.FindR(str);
			//auto ret = dict.FindR(str);
			if (ret)
			{
				cout << ret->_value << endl;
			}
			else
			{
				cout << "无此单词" << endl;
			}
		}
	}

KV模型

KV模型,对于每一个关键码key,都有与之对应的值value,即<key, value>的键值对。

英汉词典就是英文与中文的对应关系,即<word, Chinese>就构成一种键值对。具体方式如下

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

完整代码

普通版本

#pragma once 

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:
	BSTree()
		:_root(nullptr)
	{

	}

	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);
			
		
			//不知道parent在那一边,需要进一步判断
			if (parent->_key > key)
			{
				//parent在左边
				parent->_left = cur;
			}
			else if (parent->_key < key)
			{
				//parent在右边
				parent->_right = cur;

			}
			else
			{
				return false;
			}
		

		return true;
	}
	bool Find(const K & key)
	{
		Node* cur = _root;
		while (cur)
		{
			if (cur->_left > key)
			{
				cur = cur->_left;
			}
			else if (cur->_left < key)
			{
				cur = cur->_right;
			}
			else
			{
				return false;
			}
			return true;
		}
	}

	bool Erase(const K& key)
	{
		Node* parent = nullptr;//待删除节点的父节点
		Node* cur = _root;//待删除的节点

		//不是空树
		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 (cur == _root)
					{
						//将根节点改为待删除节点的右孩子
						_root = cur->_right;
					}
					//待删除节点不是根节点,并且此时parent不为nullptr
					else
					{
						

						if (parent->_right == cur)
						{
							parent->_right = cur->_right;
						}
						else//parent->_left ==cur
						{
							parent->_left = cur->_right;
						}


					}
					
				}
				

				//待删除节点的右子树为空 ,即一个孩子的情况
				else if (cur->_right == nullptr)
				{
					//待删除节点是根节点
					if (cur == _root)
					{
						//将根节点改为待删除节点的左孩子
						_root = cur->_left;
					}
					//待删除节点不是根节点,并且此时parent不为nullptr
					else
					{
						
						if (parent->_right == cur)
						{
							parent->_right = cur->_left;
						}
						else//parent->_left==cur
						{
							parent->_left = cur->_left;
						}

					}
					
				} 

				else //待删除的节点的左右孩子都不为空 (替换法:左子树的最大节点即最右节点,或者右子树的最小节点即最左节点,并且将替换的节点删除)
				{
					//替换法

					//找替代节点
					Node* parent = cur;
					//找左子树的最大节点
					Node* leftMax = cur->_left;
					
					while (leftMax->_right)
					{
						parent = leftMax; //记录leftMax的父节点,防止删除leftMax时找不到该节点位置 
						//一直往右子树找
						leftMax = leftMax->_right;
					}
					//左子树的最大节点和待删除节点替换
					swap(cur->_key, leftMax->_key);
					//重新改变链接关系
					 
					//特殊情况 
					if (parent->_left == leftMax)
					{
						parent->_left = leftMax->_left;
					}
					else//普通情况 
					{
						parent->_right = leftMax->_left;
						//parent->_right =nullptr;
					}
					cur = leftMax;


				
				}
				//删除左子树的最大节点
				delete cur;
				return true;
			}
			
		}
		return false;
	}



	//中序遍历
	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}
	
	void _InOrder(Node *root  )
	{
		if (root == nullptr)
		{
			return; 
		}
		_InOrder(root->_left);
		cout << root->_key << " ";
		_InOrder(root->_right);

	}


private:
	Node* _root;
};

void TestBSTree1()
{
	int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
	BSTree<int> t;
	for (auto e : a)
	{
		t.Insert(e);
	}
	t.InOrder();

	t.Erase(4);
	t.InOrder();

	t.Erase(6);
	t.InOrder();

	t.Erase(7);
	t.InOrder();

	t.Erase(3);
	t.InOrder();

	for (auto e : a)
	{
		t.Erase(e);
	}
	t.InOrder();

}

递归版本

#pragma once 
#include<string>
using namespace std;
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)
		{

		}
	};

	template <class K>
	class BSTree
	{
	public:
		typedef  BSTreeNode<K> Node;
	public:
		BSTree()
			:_root(nullptr)
		{

		}

		~BSTree()
		{
			Destroy(_root);
		}
		//拷贝构造
		BSTree(const  BSTree<K>& t)
			//BSTree(  BSTree<K>  *this ,  const  BSTree<K> & t)
			//t1 =t 
		{
			_root = Copy(t._root);
		}
		//赋值重载 
		BSTree<K>& operator= (BSTree<K>& t)
			//t1 = t
		{
			swap(_root, t._root);
			return *this;
		}
		bool EraseR(Node* _root, const K& key)//递归版本
		{
			return _EraseR(_root, key);
		}

		bool InsertR(const K& key)//递归版本
		{
			return _InsertR(_root, key);
		}

		bool FindR(Node* _root, const K& key)//递归版本
		{
			return _FindR(_root, key);
		}

	private:
		Node* Copy(Node* root)
		{
			if (root == nullptr)
			{
				return nullptr;
			}
			Node* copyNode = new Node(root->_key);
			//递归 
			copyNode->_left = Copy(root->_left);
			copyNode->_right = Copy(root->_right);
			return  copyNode;

		}

		void Destroy(Node*& root) //引用的目的:将每个节点释放后同时置空
		{
			//后序遍历 
			if (root == nullptr)
			{
				return;
			}
			Destroy(root->_left);
			Destroy(root->_right);
			delete root;
			root = nullptr;
		}
		bool _InsertR(Node*& root, const K& key) //引用的目的:不用找父节点,不需要用父节点比较大小
		{
			//结束条件
			if (root == nullptr)
			{
				root = new Node(key);
				return true;
			}
			//往左子树走
			if (root->_key > key)
			{
				return _InsertR(root->_left, key);
			}
			//往右子树走
			else if (root->_key < key)
			{
				return _InsertR(root->_right, key);

			}
			else
			{
				return false;
			}
		}

		bool _EraseR(Node*& root, const K& key)//引用的目的:不用找父节点,不需要用父节点比较大小
		{
			//结束条件
			if (root == nullptr)
			{
				return false;
			}
			//往左树找
			if (root->_key > key)
			{
				return _EraseR(root->_left, key);
			}
			//往右树找
			else if (root->_key < key)
			{
				return _EraseR(root->_right, key);
			}
			else//找到,开始删除
			{
				Node* del = root;
				//待删除节点的左子树为空 ,即一个孩子的情况
				if (root->_left == nullptr)
				{
					root = root->_right;
				}


				//待删除节点的右子树为空 ,即一个孩子的情况
				else if (root->_right == nullptr)
				{
					root = root->_left;
				}
				//待删除的节点的左右孩子都不为空 (替换法:左子树的最大节点即最右节点,或者右子树的最小节点即最左节点,并且将替换的节点删除)
				else
				{
					//找左子树最大节点
					Node* leftMax = root->_left;
					//一直往左边找,直到找到左子树最大节点
					while (root->_left)
					{
						root = root->_left;
					}
					//将左子树最大节点与被删除节点替换
					swap(leftMax->_key, root->_key);

					return _EraseR(root, key);
				}

				delete del;//?
				return true;

			}


		}

		bool  _FindR(Node* root, const K& key)
		{
			//结束条件
			if (root == nullptr)
			{
				return false;
			}

			if (root->_key > key)
			{
				return _FindR(root->_left, key);
			}
			else if (root->_key < key)
			{
				return _FindR(root->_right, key);
			}
			else
			{
				return true;
			}
		}



	public:
		//中序遍历
		void InOrder()
		{
			_InOrder(_root);
			cout << endl;
		}

		void _InOrder(Node* root)
		{
			if (root == nullptr)
			{
				return;
			}
			_InOrder(root->_left);
			cout << root->_key << " ";
			_InOrder(root->_right);

		}

	public:
		Node* _root;
	};


	void TestBSTree1()
	{
		int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
		BSTree<int> t;
		for (auto e : a)
		{
			t.InsertR(e);
		}

		t.InOrder();
		//没有引用,释放了,只是指针没有置空,尤其是根节点_root,我们还能通过他找到
		/*t.Destroy(t._root);*/

		t.EraseR(t._root, 4);
		t.InOrder();

		t.EraseR(t._root, 6);
		t.InOrder();

		t.EraseR(t._root, 7);
		t.InOrder();

		t.EraseR(t._root, 3);
		t.InOrder();

		for (auto e : a)
		{
			t.EraseR(t._root, e);
		}
		t.InOrder();
	}

	void TestBSTree2()
	{
		int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
		BSTree<int> t;
		for (auto e : a)
		{
			t.InsertR(e);
		}
		t.InOrder();
		BSTree<int> t1(t);
		t.InOrder();
		t1.InOrder();


	}
}

namespace 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
	{
	public:
		typedef BSTreeNode<K, V> Node;
	public:
		BSTree()
			:_root(nullptr)
		{}

		void InOrder()
		{
			_InOrder(_root);
			cout << endl;
		}

		Node* FindR(const K& key)
		{
			return _FindR(_root, key);
		}

		bool InsertR(const K& key, const V& value)
		{
			return _InsertR(_root, key, value);
		}

		bool EraseR(const K& key)
		{
			return _EraseR(_root, key);
		}

	private:
		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;

				// 1、左为空
				// 2、右为空
				// 3、左右都不为空
				if (root->_left == nullptr)
				{
					root = root->_right;
				}
				else if (root->_right == nullptr)
				{
					root = root->_left;
				}
				else
				{
					Node* leftMax = root->_left;
					while (leftMax->_right)
					{
						leftMax = leftMax->_right;
					}

					swap(root->_key, leftMax->_key);

					return _EraseR(root->_left, key);
				}

				delete del;
				return true;
			}
		}

		bool _InsertR(Node*& root, const K& key, const V& value)
		{
			if (root == nullptr)
			{
				root = new Node(key, value);
				return true;
			}

			if (root->_key < key)
			{
				return _InsertR(root->_right, key, value);
			}
			else if (root->_key > key)
			{
				return _InsertR(root->_left, key, value);
			}
			else
			{
				return false;
			}
		}

		Node* _FindR(Node* root, const K& key)
		{
			if (root == nullptr)
				return nullptr;

			if (root->_key < key)
			{
				return _FindR(root->_right, key);
			}
			else if (root->_key > key)
			{
				return _FindR(root->_left, key);
			}
			else
			{
				return root;
			}
		}

		void _InOrder(Node* root)
		{
			if (root == NULL)
			{
				return;
			}

			_InOrder(root->_left);
			cout << root->_key << ":" << root->_value << endl;
			_InOrder(root->_right);
		}
	private:
		Node* _root;
	};

	void TestBSTree1()
	{
		
		BSTree<string, string > dict;
		dict.InsertR("insert", "插入");
		dict.InsertR("sort", "排序");
		dict.InsertR("right", "右边");
		dict.InsertR("date", "日期");
		
		string str;
		while (cin>>str)
		{
			
			auto * ret  = dict.FindR(str);
			//auto ret = dict.FindR(str);
			if (ret)
			{
				cout << ret->_value << endl;
			}
			else
			{
				cout << "无此单词" << endl;
			}
		}
	}
	void TestBSTree2()
	{
		string arr[] = {"西瓜", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
		BSTree<string, int > countTree;
		for (auto &str : arr)
		{
			auto ret = countTree.FindR(str);
			if (ret == nullptr)
			{
				countTree.InsertR(str,1);
			
			}
			else
			{
				ret->_value++;
			}
		}
		countTree.InOrder();
	}

}

如果你觉得这篇文章对你有帮助,不妨动动手指给点赞收藏加转发,给鄃鳕一个大大的关注你们的每一次支持都将转化为我前进的动力!!!文章来源地址https://www.toymoban.com/news/detail-723736.html

到了这里,关于搜索二叉树【C++】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构——常见二叉树的分类(完全二叉树、满二叉树、平衡二叉树、二叉搜索树、红黑树)

    专业术语 中文 描述 Root 根节点 一棵树的顶点 Child 孩子结点 一个结点含有的子树的根节点称为该结点的子节点 Leaf 叶子结点 没有孩子的节点 Degree 度 一个节点包含子树的数量 Edge 边 一个节点与另外一个节点的连接 Depth 深度 根节点到这个节点经过边的数量 Height 节点高度 从

    2024年02月03日
    浏览(44)
  • 数据结构第四天: Complete Binary Search Tree 【搜索二叉树,完全二叉树】

     这道题需要的操作时排序并且需要遍历,最重要的一点它是个完全二叉树,所以数组是最适合的 这道题我的思路来自于浙江大学课件7.0.2完全二叉树 这道题说白就是将输入的样例构造成一个完全搜索二叉树。因为完全线索二叉树的 根节点一定是是一个处于左右子树中间的那

    2024年02月06日
    浏览(55)
  • 〖数据结构〗一棵有点自律的树——搜索二叉树

    🌸作者简介: 花想云 ,在读本科生一枚,致力于 C/C++、Linux 学习。 🌸 本文收录于 C++系列 ,本专栏主要内容为 C++ 初阶、C++ 进阶、STL 详解等,专为大学生打造全套 C++ 学习教程,持续更新! 🌸 相关专栏推荐: C语言初阶系列 、 C语言进阶系列 、 数据结构与算法 、 Linu

    2024年02月08日
    浏览(42)
  • (浙大陈越版)数据结构 第三章 树(中) 二叉搜索树和平衡二叉树

    目录 4.1.1 二叉搜索树及查找 什么是二叉搜索树 定义 二叉搜索树特殊函数集: 查找操作:Find 算法思想 代码实现 补:查找最大和最小元素 4.1.2 二叉搜索树的插入 插入操作:Insert 算法思想 代码实现 例题 4.1.3 二叉搜索树的删除 删除操作:delete 算法思想 情况1:删除叶节点

    2024年02月08日
    浏览(55)
  • 数据结构与算法之二叉树: Leetcode 98. 验证二叉搜索树 (Typescript版)

    验证二叉搜索树 https://leetcode.cn/problems/validate-binary-search-tree/ 描述 给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树 有效 二叉搜索树定义如下: 节点的左子树只包含 小于 当前节点的数。 节点的右子树只包含 大于 当前节点的数。 所有左子树和右子树自身

    2024年02月16日
    浏览(40)
  • 数据结构之进阶二叉树(二叉搜索树和AVL树、红黑树的实现)超详细解析,附实操图和搜索二叉树的实现过程图

    绪论​ “生命有如铁砧,愈被敲打,愈能发出火花。——伽利略”;本章主要是数据结构 二叉树的进阶知识,若之前没学过二叉树建议看看这篇文章一篇掌握二叉树,本章的知识从浅到深的 对搜索二叉树的使用进行了介绍和对其底层逻辑的实现进行了讲解 ,希望能对你有所

    2024年02月04日
    浏览(46)
  • 数据结构与算法(三):树论(树形结构、二叉树、二叉搜索树、红黑树、Btree&B+Tree、赫夫曼树、堆树)

    树论(树形结构、二叉树、二叉搜索树、红黑树、Btree、B+Tree、赫夫曼树、堆树) 在树形结构里面重要的术语: 结点:树里面的元素。 父子关系:结点之间相连的边 子树:当结点大于1时,其余的结点分为的互不相交的集合称为子树 度:一个结点拥有的子树数量称为结点的

    2024年02月01日
    浏览(94)
  • 数据结构第十六天(二叉树层序遍历/广度优先搜索(BFS)/队列使用)

    目录 前言 概述 接口 源码 测试函数 运行结果 往期精彩内容 从前的日色变得慢,车,马,邮件都慢,一生,只够爱一个人。 二叉树的层序遍历可以使用广度优先搜索(BFS)来实现。具体步骤如下: 创建一个队列 queue,并将根节点入队。 当队列不为空时,重复执行以下步骤:

    2024年02月22日
    浏览(36)
  • 【Java 数据结构】二叉树

    树是一种 非线性 的数据结构,它是由n(n=0)个有限结点组成一个具有层次关系的集合。 把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的 。 有一个特殊的结点,称为根结点,根结点没有前驱结点 除根结点外,其余结点被分成M(M 0)个互不相交的

    2024年02月20日
    浏览(46)
  • 【java数据结构-二叉树(上)】

    🔥个人主页: 努力学编程’ 🔥内容管理: java数据结构 hello,今天带大家学习 数据结构 中非常重要的一个知识点 二叉树 ,二叉树主体的实现使用的是递归的知识,通过二叉树我们可以更好的理解递归的应用。今天就带大家学习一下二叉树的一些知识。 概念 : 树是一种非

    2024年04月08日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包