【C++庖丁解牛】二叉搜索树(Binary Search Tree,BST),C++深度解析,二叉搜索树(Binary Search Tree,BST)原理与实现

马肤

温馨提示:这篇文章已超过468天没有更新,请注意相关的内容是否还可用!

摘要:本文介绍了二叉搜索树(Binary Search Tree,BST)在C++中的实现原理与操作。二叉搜索树是一种特殊的二叉树,其每个节点都存储一个关键字,并允许进行快速查找、插入和删除操作。本文详细解析了二叉搜索树的结构特点、构建方法以及遍历方式,帮助读者深入理解这一数据结构的应用与优势。
【C++庖丁解牛】二叉搜索树(Binary Search Tree,BST),C++深度解析,二叉搜索树(Binary Tree,BST)原理与实现 第1张 🍁你好,我是 RO-BERRY 📗 致力于C、C++、数据结构、TCP/IP、数据库等等一系列知识 🎄感谢你的陪伴与支持 ,故事既有了开头,就要画上一个完美的句号,让我们一起加油

【C++庖丁解牛】二叉搜索树(Binary Search Tree,BST),C++深度解析,二叉搜索树(Binary Tree,BST)原理与实现 第2张


目录

  • 1. 二叉搜索树概念
  • 2. 二叉搜索树操作
  • 3. 二叉搜索树的实现
    • 3.1 准备工作
      • 结点结构体BSTreeNode
      • 二叉搜索树BinarySearchTree
      • 3.2 函数体实现
        • 📖bool Insert(const K& key)
        • 📖bool Find(const K& key)
        • 📖打印二叉搜索树void InOrder()
        • 📖删除 Erase
        • 📖构造函数、析构函数、拷贝构造以及复制拷贝
        • 3.3 函数体实现(优化版)
          • 📖优化版insert函数
          • 📖优化版find函数
          • 📖优化版Erase函数
          • 3.4 源代码BinarySearchTree.h
          • 4. 二叉搜索树的应用
            • kv二叉树实现
            • 5. 二叉搜索树的性能分析

              1. 二叉搜索树概念

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

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

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

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

              二叉搜索树(Binary Search Tree,简称BST)是种常用的数据结构,它是一棵二叉树,并且满足以下性质:

              对任意节点,其左子树中的节点的值都小于该节点的值。

              对于任意节点,其右子树中的所有节点的值都大于该节点的值。

              左子树和右子树也都是二叉搜索树。

              二叉搜索树的这种特性使得它在查找、插入和删除操作上具有高效性能。通过比较节点的值,可以快速定位到目标节点或者确定插入位置。

              二叉搜索树的操作包括:

              查找:从根节点开始,递归地比较目标值与当前节点的值,直到找到目标节点或者遍历到叶子节点。

              插入:从根节点开始,递归地比较目标值与当前节点的值,根据大小关系选择左子树或右子树进行插入,直到找到合适的插入位置。

              删除:删除操作比较复杂,需要考虑被删除节点的子节点情况。可以分为三种情况:被删除节点没有子节点、被删除节点只有一个子节点、被删除节点有两个子节点。

              二叉搜索树的时间复杂度取决于树的高度,平均情况下为O(log n),最坏情况下为O(n)。为了保持树的平衡,可以使用平衡二叉搜索树(如AVL树、红黑树)来优化性能。

              【C++庖丁解牛】二叉搜索树(Binary Search Tree,BST),C++深度解析,二叉搜索树(Binary Tree,BST)原理与实现 第3张

              2. 二叉搜索树操作

              【C++庖丁解牛】二叉搜索树(Binary Search Tree,BST),C++深度解析,二叉搜索树(Binary Tree,BST)原理与实现 第4张

              int a[] = {8, 3, 1, 10, 6, 4, 7, 14, 13};
              
              1. 二叉搜索树的查找

                a、从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。

                b、最多查找高度次,走到到空,还没找到,这个值不存在。

              2. 二叉搜索树的插入

                插入的具体过程如下:

                a. 树为空,则直接新增节点,赋值给root指针

                b. 树不空,按二叉搜索树性质查找插入位置,插入新节点

              【C++庖丁解牛】二叉搜索树(Binary Search Tree,BST),C++深度解析,二叉搜索树(Binary Tree,BST)原理与实现 第5张

              1. 二叉搜索

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

              a. 要删除的结点无孩子结点

              b. 要删除的结点只有左孩子结点

              c. 要删除的结点只有右孩子结点

              d. 要删除的结点有左、右孩子结点

              看起来有待删除节点有4中情况,实际情况a可以与情况b或者c合并起来,因此真正的删除过程如下:

              情况b:删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点–直接删除

              情况c:删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点–直接删除

              情况d:在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,再来处理该结点的删除问题–替换法删除

              【C++庖丁解牛】二叉搜索树(Binary Search Tree,BST),C++深度解析,二叉搜索树(Binary Tree,BST)原理与实现 第6张

              3. 二叉搜索树的实现

              3.1 准备工作

              结点结构体BSTreeNode

              我们实现二叉搜索树需要定义其结点,定义其左右节点以及value,方便后续操作进行

              template
              struct BSTreeNode      //二叉树结点
              {
              	typedef BSTreeNode Node;     //简化名称
              	Node* _left;        //左节点
              	Node* _right;       //右节点
              	K _key;             //结点value
              	BSTreeNode(const K& key)    //构造函数
              		:_left(nullptr)
              		,_right(nullptr)
              		,_key(key)
              	{}
              };
              

              二叉搜索树BinarySearchTree

              template
              class BinarySearchTree
              {
              	typedef BSTreeNode Node;    //节点名称简化
              public:
              	.....         //二叉搜索树函数接口
              private:
              	Node* _root = nullptr;        //省略了初始化在定义的时候就进行初始化
              };
              

              3.2 函数体实现

              📖bool Insert(const K& key)

              实现思路:

              二叉搜索树的定义是左边的子结点必定小于父节点,右边的子结点必定大于父节点,所以我们采取key值与节点value比较,如果key大于节点value,则继续与节点右子节点比较;如果key小于节点value,则继续与节点左子节点比较,最终如果走到空的位置,则进行插入。

              这里我们需要定义一个parent节点帮助我们定位最终插入后其父节点的位置,然后将父节点与新插入的结点进行连接,将父节点的value与key值比较,若key大于value,那么肯定是被插入到父节点的右子树里了;若key小于value,则反之。

              另:我们要独自判断空树的情况,不然会出现程序崩溃;搜索二叉树的每一个节点数值不能一样,那么我们如果插入的key与某个value相等,也会返回false

              实现代码:

              	bool Insert(const K& key)
              	{
              		if (_root == nullptr)
              		{
              			_root = new Node(key);
              			return true;
              		}
              		Node* cur = _root;
              		Node* parent = nullptr;    //父节点
              		while (cur)
              		{
              			if (cur->_key _right;
              			}
              			else if ((cur->_key > key))
              			{
              				parent = cur;
              				cur = cur->_left;
              			}
              			else
              			{
              				return false;
              			}
              		}
              		cur = new Node(key);
              		if (parent->_key _right = cur;
              		}
              		else
              		{
              			parent->_left = cur;
              		}
              		return true;
              	}
              

              📖bool Find(const K& key)

              实现思路:

              左边的子结点必定小于父节点,右边的子结点必定大于父节点,所以我们采取key值与节点value比较,如果key大于节点value,则继续与节点右子节点比较;如果key小于节点value,则继续与节点左子节点比较,最终如果走到空的位置,则返回false,如果找到与key相等的value,则返回true。

              实现代码:

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

              📖打印二叉搜索树void InOrder()

              实现思路:

              使用递归实现中序遍历,二叉搜索树的中序遍历其实输出出来是一个递增排序的数组,从根节点开始,访问其左子树,并进行打印,然后访问右子树进行打印。

              这里用了一个巧妙的方法: 我们对二叉搜索树打印需要传入根节点位置,才能进行递归,但是根节点为私有成员,我们要么写一个GetRoot()函数获取到根节点位置,才能传入,我们在这里可以对其进行封装,在上面重新定义一个打印函数,然后在这个函数里面调用刚刚的打印函数,并传入root,这样就不用在调用的时候传入root了。

              实现代码:

              	void InOrder()       //巧妙调用输出函数
              	{
              		_InOrder(_root);
              		cout 
              		if (root == nullptr)
              			return;
              		_InOrder(root-_left);
              		cout _key _right);
              	}
              

              📖删除 Erase

              实现思路:

              二叉搜索树(Binary Search Tree,BST)的删除操作是指在BST中删除一个指定的节点。删除操作的模拟实现可以按照以下步骤进行:

              首先,需要找到要删除的节点。从根节点开始,比较要删除的节点值与当前节点值的大小关系,如果相等则找到了要删除的节点,如果小于当前节点值,则继续在左子树中查找,如果大于当前节点值,则继续在右子树中查找。重复这个过程直到找到要删除的节点或者遍历到叶子节点为止。

              如果找到了要删除的节点,需要考虑以下几种情况:

              1. 如果要删除的节点是叶子节点(没有子节点),直接删除即可。
              2. 如果要删除的节点只有一个子节点,将其子节点替代要删除的节点即可。
              3. 如果要删除的节点有两个子节点,需要找到其右子树中的最小节点(或者左子树中的最大节点),将其值替换到要删除的节点上,并将最小(或最大)节点删除。

              实现删除操作时,需要注意维护BST的性质,即左子树中的所有节点值都小于当前节点值,右子树中的所有节点值都大于当前节点值。

              实现代码:

              	bool Erase(const K& key)
              	{
              		Node* parent = nullptr;
              		Node* cur = _root;
              		while (cur)
              		{
              			if (cur->_key _right;
              			}
              			else if (cur->_key > key)
              			{
              				parent = cur;
              				cur = cur->_left;
              			}
              			else
              			{
              				if (cur->_left == nullptr)   //左子树为空
              				{
              					if (cur == _root)
              					{
              						_root = cur->_right;
              					}
              					else
              					{
              						if (cur == parent->_right)
              						{
              							parent->_right = cur->_right;
              						}
              						else
              						{
              							parent->_left = cur->_right;
              						}
              					}
              					delete cur;
              					return true;
              				}
              				else if (cur->_right == nullptr)  //右子树为空
              				{
              					if (cur == _root)
              					{
              						_root = cur->_left;
              					}
              					else
              					{
              						if (cur == parent->_right)
              						{
              							parent->_right = cur->_left;
              						}
              						else
              						{
              							parent->_left = cur->_left;
              						}
              					}
              					delete cur;
              					return true;
              				}
              				else                          //左右子树都不为空
              				{
              					// 替换法
              					Node* rightMinParent = cur;
              					Node* rightMin = cur->_right;
              					while (rightMin->_left)
              					{
              						rightMinParent = rightMin;
              						rightMin = rightMin->_left;
              					}
              					cur->_key = rightMin->_key;
              					if (rightMin == rightMinParent->_left)     //根节点
              						rightMinParent->_left = rightMin->_right;    
              					else
              						rightMinParent->_right = rightMin->_right;
              					delete rightMin;
              					return true;
              				}
              			}
              		}
              		return false;
              	}
              

              📖构造函数、析构函数、拷贝构造以及复制拷贝

              这里直接实现,不再讲述原理,因为这一块比较基础了

              	//强制生成默认构造
              	BinarySearchTree() = default;
              	BinarySearchTree(const BinarySearchTree& t)   //拷贝构造函数
              	{
              		_root = Copy(t._root);
              	}
              	Node* Copy(Node* root)
              	{
              		if (root == nullptr)
              			return nullptr;
              		Node* newRoot = new Node(root->_key);
              		newRoot->_left = Copy(root->_left);
              		newRoot->_right = Copy(root->_right);
              		return new Root;
              	}
              	BinarySearchTree& operator=(const BinarySearchTree& t)    //赋值拷贝
              	{
              		swap(_root, t._root);
              		return *this;
              	}
              	~BinarySearchTree()   //析构函数
              	{
              		Destroy(_root);
              	}
              

              3.3 函数体实现(优化版)

              我们的优化主要用了封装的艺术

              📖优化版insert函数

              我们在上面的函数实现时需要判断最终在左子树还是在右子树,并且还要定义一个parent来存储其父节点,而我们对其进行优化,可以看到我们在函数参数里加了一个Node*& root,正是这个参数,我们使用了引用,就不需要再判断其是左子树还是右子树,也不用记录其父节点,因为引用就是别名,我们对其进行修改就是对这个指针进行修改,这里还用了递归,让我们的代码量大大减小

              public:
              	bool InsertR(const K& key)      //函数放在public便于访问
              	{
              		return _InsertR(_root, key);
              	}
              private:                              //函数的具体实现放在private
              	bool _InsertR(Node*& root,const K& key)   //这里使用别名,修改的就是其本身,就不用判断左右节点了
              	{
              		if (root == nullptr)
              		{
              			root=new Node(key);
              			return true;
              		}
              		if (root->_key _right, key);
              	}
              		else if (root->_key > key)            //大于key就遍历左子树
              		{
              			return _InsertR(root->_left, key);  
              		}
              		else
              		{
              			return false;
              		}
              	}
              

              📖优化版find函数

              public:
              	bool FindR(const K& key)
              	{
              		return _FindR(_root, key);
              	} 
              private:
              	bool _FindR(Node* root,const K& key)
              	{
              		if (root == nullptr)
              			return false;
              		if (root->_key _right, key);
              		}
              		else if (root->_key > key)
              		{
              			return _FindR(root->_left, key);
              		}
              		else
              		{
              			return true;
              		}
              	}
              

              📖优化版Erase函数

              public:
              	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 _right, key);
              		}
              		else if (root->_key > key)
              		{
              			return _EraseR(root->_left, key);
              		}
              		else
              		{
              			Node* del = root;     //保存该节点便于删除
              			if (root->_right == nullptr)
              			{
              				root = root->_left;
              			}
              			else if (root->_left == nullptr)
              			{
              				root = root->_right;
              			}
              			else
              			{
              				Node* rightMin = root->_right;
              				while (rightMin->_left)
              				{
              					rightMin = rightMin->_left;
              				}
              				swap(root->_key, rightMin->_key);
              				return _EraseR(root->_right, key);
              			}
              			delete del;
              			return true;
              		}
              	}
              

              3.4 源代码BinarySearchTree.h

              #pragma once
              #include
              using namespace std;
              template
              struct BSTreeNode
              {
              	typedef BSTreeNode Node;
              	Node* _left;
              	Node* _right;
              	K _key;
              	BSTreeNode(const K& key)
              		:_left(nullptr)
              		,_right(nullptr)
              		,_key(key)
              	{}
              };
              template
              class BinarySearchTree
              {
              	typedef BSTreeNode Node;
              public:
              	//强制生成默认构造
              	BinarySearchTree() = default;
              	BinarySearchTree(const BinarySearchTree& t)   //拷贝构造函数
              	{
              		_root = Copy(t._root);
              	}
              	Node* Copy(Node* root)
              	{
              		if (root == nullptr)
              			return nullptr;
              		Node* newRoot = new Node(root->_key);
              		newRoot->_left = Copy(root->_left);
              		newRoot->_right = Copy(root->_right);
              		return new Root;
              	}
              	BinarySearchTree& operator=(const BinarySearchTree& t)    //赋值拷贝
              	{
              		swap(_root, t._root);
              		return *this;
              	}
              	~BinarySearchTree()   //析构函数
              	{
              		Destroy(_root);
              	}
              	bool Insert(const K& key)
              	{
              		if (_root == nullptr)
              		{
              			_root = new Node(key);
              			return true;
              		}
              		Node* cur = _root;
              		Node* parent = nullptr;    //父节点
              		while (cur)
              		{
              			if (cur->_key _right;
              			}
              			else if ((cur->_key > key))
              			{
              				parent = cur;
              				cur = cur->_left;
              			}
              			else
              			{
              				return false;
              			}
              		}
              		cur = new Node(key);
              		if (parent->_key _right = cur;
              		}
              		else
              		{
              			parent->_left = cur;
              		}
              		return true;
              	}
              	bool Find(const K& key)
              	{
              		Node* cur = _root;
              		while (cur)
              		{
              			if (cur->_key _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 _right;
              			}
              			else if (cur->_key > key)
              			{
              				parent = cur;
              				cur = cur->_left;
              			}
              			else
              			{
              				if (cur->_left == nullptr)   //左子树为空
              				{
              					if (cur == _root)
              					{
              						_root = cur->_right;
              					}
              					else
              					{
              						if (cur == parent->_right)
              						{
              							parent->_right = cur->_right;
              						}
              						else
              						{
              							parent->_left = cur->_right;
              						}
              					}
              					delete cur;
              					return true;
              				}
              				else if (cur->_right == nullptr)  //右子树为空
              				{
              					if (cur == _root)
              					{
              						_root = cur->_left;
              					}
              					else
              					{
              						if (cur == parent->_right)
              						{
              							parent->_right = cur->_left;
              						}
              						else
              						{
              							parent->_left = cur->_left;
              						}
              					}
              					delete cur;
              					return true;
              				}
              				else                          //左右子树都不为空
              				{
              					// 替换法
              					Node* rightMinParent = cur;
              					Node* rightMin = cur->_right;
              					while (rightMin->_left)
              					{
              						rightMinParent = rightMin;
              						rightMin = rightMin->_left;
              					}
              					cur->_key = rightMin->_key;
              					if (rightMin == rightMinParent->_left)     //根节点
              						rightMinParent->_left = rightMin->_right;    
              					else
              						rightMinParent->_right = rightMin->_right;
              					delete rightMin;
              					return true;
              				}
              			}
              		}
              		return false;
              	}
              	void InOrder()       //巧妙调用输出函数
              	{
              		_InOrder(_root);
              		cout 
              		return _FindR(_root, key);
              	} 
              	bool InsertR(const K& key)
              	{
              		return _InsertR(_root, key);
              	}
              	bool EraseR(const K& key)
              	{
              		return _EraseR(_root, key);
              	}
              private:
              	void Destroy(Node* root)
              	{
              		if (root == nullptr)
              			return;
              		Destroy(root-_left);
              		Destroy(root->_right);
              		delete root;
              	}
              	bool _EraseR(Node*& root, const K& key)
              	{
              		if (root == nullptr)
              			return false;
              		if (root->_key _right, key);
              		}
              		else if (root->_key > key)
              		{
              			return _EraseR(root->_left, key);
              		}
              		else
              		{
              			Node* del = root;     //保存该节点便于删除
              			if (root->_right == nullptr)
              			{
              				root = root->_left;
              			}
              			else if (root->_left == nullptr)
              			{
              				root = root->_right;
              			}
              			else
              			{
              				Node* rightMin = root->_right;
              				while (rightMin->_left)
              				{
              					rightMin = rightMin->_left;
              				}
              				swap(root->_key, rightMin->_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 _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 _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 _key _right);
              	}
              	Node* _root = nullptr;
              };
              

              4. 二叉搜索树的应用

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

              比如:

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

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

              1. KV模型:每一个关键码key,都有与之对应的值Value,即的键值对。该种方式在现实生活中非常常见:

              比如:

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

              kv二叉树实现

              namespace key_value
              {
              	template
              	struct BSTreeNode
              	{
              		typedef BSTreeNode Node;
              		Node* _left;
              		Node* _right;
              		K _key;
              		V _value;
              		BSTreeNode(const K& key, const V& value)
              			:_left(nullptr)
              			,_right(nullptr)
              			,_key(key)
              			,_value(value)
              		{}
              	};
              	template
              	class BSTree
              	{
              		typedef BSTreeNode 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 _right;
              				}
              				else if (cur->_key > key)
              				{
              					parent = cur;
              					cur = cur->_left;
              				}
              				else
              				{
              					return false;
              				}
              			}
              			cur = new Node(key, value);
              			if (parent->_key _right = cur;
              			}
              			else
              			{
              				parent->_left = cur;
              			}
              			return true;
              		}
              		Node* Find(const K& key)
              		{
              			Node* cur = _root;
              			while (cur)
              			{
              				if (cur->_key _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 _right;
              				}
              				else if (cur->_key > key)
              				{
              					parent = cur;
              					cur = cur->_left;
              				}
              				else
              				{
              					if (cur->_left == nullptr)
              					{
              						if (cur == _root)
              						{
              							_root = cur->_right;
              						}
              						else
              						{
              							if (cur == parent->_right)
              							{
              								parent->_right = cur->_right;
              							}
              							else
              							{
              								parent->_left = cur->_right;
              							}
              						}
              						delete cur;
              						return true;
              					}
              					else if (cur->_right == nullptr)
              					{
              						if (cur == _root)
              						{
              							_root = cur->_left;
              						}
              						else
              						{
              							if (cur == parent->_right)
              							{
              								parent->_right = cur->_left;
              							}
              							else
              							{
              								parent->_left = cur->_left;
              							}
              						}
              						delete cur;
              						return true;
              					}
              					else
              					{
              						// 替换法
              						Node* rightMinParent = cur;
              						Node* rightMin = cur->_right;
              						while (rightMin->_left)
              						{
              							rightMinParent = rightMin;
              							rightMin = rightMin->_left;
              						}
              						cur->_key = rightMin->_key;
              						if (rightMin == rightMinParent->_left)
              							rightMinParent->_left = rightMin->_right;
              						else
              							rightMinParent->_right = rightMin->_right;
              						delete rightMin;
              						return true;
              					}
              				}
              			}
              			return false;
              		}
              		void InOrder()
              		{
              			_InOrder(_root);
              			cout 
              			if (root == nullptr)
              				return;
              			_InOrder(root-_left);
              			cout _key _right);
              		}
              	private:
              		Node* _root = nullptr;
              	};
              }
              

              5. 二叉搜索树的性能分析

              插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。

              对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。

              但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树:

              【C++庖丁解牛】二叉搜索树(Binary Search Tree,BST),C++深度解析,二叉搜索树(Binary Tree,BST)原理与实现 第7张

              1. 最优情况下,二叉搜索树为完全二叉树(或者接近完全二叉树),其平均比较次数为: l o g 2 N log_2 N log2​N
              2. 最差情况下,二叉搜索树退化为单支树(或者类似单支),其平均比较次数为: N 2 \frac{N}{2} 2N​

              问题:如果退化成单支树,二叉搜索树的性能就失去了。那能否进行改进,不论按照什么次序插

              入关键码,二叉搜索树的性能都能达到最优?那么我们后续章节学习的AVL树和红黑树就可以上

              场了。


0
收藏0
文章版权声明:除非注明,否则均为VPS857原创文章,转载或复制请以超链接形式并注明出处。

相关阅读

  • 【研发日记】Matlab/Simulink自动生成代码(二)——五种选择结构实现方法,Matlab/Simulink自动生成代码的五种选择结构实现方法(二),Matlab/Simulink自动生成代码的五种选择结构实现方法详解(二)
  • 超级好用的C++实用库之跨平台实用方法,跨平台实用方法的C++实用库超好用指南,C++跨平台实用库使用指南,超好用实用方法集合,C++跨平台实用库超好用指南,方法与技巧集合
  • 【动态规划】斐波那契数列模型(C++),斐波那契数列模型(C++实现与动态规划解析),斐波那契数列模型解析与C++实现(动态规划)
  • 【C++】,string类底层的模拟实现,C++中string类的模拟底层实现探究
  • uniapp 小程序实现微信授权登录(前端和后端),Uniapp小程序实现微信授权登录全流程(前端后端全攻略),Uniapp小程序微信授权登录全流程攻略,前端后端全指南
  • Vue脚手架的安装(保姆级教程),Vue脚手架保姆级安装教程,Vue脚手架保姆级安装指南,Vue脚手架保姆级安装指南,从零开始教你如何安装Vue脚手架
  • 如何在树莓派 Raspberry Pi中本地部署一个web站点并实现无公网IP远程访问,树莓派上本地部署Web站点及无公网IP远程访问指南,树莓派部署Web站点及无公网IP远程访问指南,本地部署与远程访问实践,树莓派部署Web站点及无公网IP远程访问实践指南,树莓派部署Web站点及无公网IP远程访问实践指南,本地部署与远程访问详解,树莓派部署Web站点及无公网IP远程访问实践详解,本地部署与远程访问指南,树莓派部署Web站点及无公网IP远程访问实践详解,本地部署与远程访问指南。
  • vue2技术栈实现AI问答机器人功能(流式与非流式两种接口方法),Vue2技术栈实现AI问答机器人功能,流式与非流式接口方法探究,Vue2技术栈实现AI问答机器人功能,流式与非流式接口方法详解
  • 发表评论

    快捷回复:表情:
    评论列表 (暂无评论,0人围观)

    还没有评论,来说两句吧...

    目录[+]

    取消
    微信二维码
    微信二维码
    支付宝二维码