数据结构—BST

本文详细介绍了二叉搜索树(BST),包括其定义、性质、数据结构及各种常见操作,如插入、删除、查找、遍历等,并探讨了如何实现非递归和递归方法来处理这些操作,同时涵盖了如何判断一个二叉树是否为BST以及找到满足特定条件的元素等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二叉树的简要概述

二叉树的定义

定于:二叉树是有限元素的集合,该集合或者为空、或者由一个称为根的元素以及两个不相交的、被称为左子树和右子树的二叉树组成。

在二叉树中,一个元素也称作一个结点。当集合为空时,称该二叉树为空二叉树

二叉树是有序的,即若将其左、右子树颠倒,就成为另一棵不同的树。

树中某个结点只有一棵树时要区分它是左子树还是右子树(这是二叉树和数之间的基本区别点)

二叉树具有五种基本形态

  • 空二叉树
  • 只有一个根
  • 只有左孩子
  • 只有右孩子
  • 有两个孩子的二叉树

在这里插入图片描述

满二叉树

  • 如果所有分支结点都存在左子树和右子树
  • 并且所有叶子结点都在同一层上

在这里插入图片描述

完全二叉树

一颗深度为k的有n个结点的二叉树,如果其中任何结点的的编号i(1≤i≤n)与满二叉树中的编号为i的结点位置完全相同,则这棵二叉树称为完全二叉树。

完全二叉树的特点

  • 叶子结点只能出现在最下层和次下层
  • 最下层的叶子结点连续出现在树的左部。

满二叉树必定是完全二叉树,而完全二叉树未必是满二叉树。

在这里插入图片描述

二叉树的主要性质

  • 一棵非空二叉树的第i层最多有 2 i − 1 2^{i-1} 2i1 个结点(i≥1).
  • 一棵深度为K的二叉树中,最多有 2 k − 1 2^k-1 2k1个结点
  • 对于一颗非空的二叉树,如果叶子结点为n0,度数为2的结点数为n2,则有
n0=n2+1
  • 具有n个结点的完全二叉树的深度k为 l o g 2 n log _2 n log2n+1
  • 对于具有n个结点的完全二叉树,如果按照从上到下、从左到右的编号体系对二叉树种的结点进行从1开始顺序编号,则对于任意的序号为i的结点,有:
  • 如果i>1,则序号为i的结点的父亲结点的序号为 ⌊ i / 2 ⌋ \lfloor i/2 \rfloor i/2;如果i=1,则序号为i的结点是根结点,无父亲结点
  • 如果2i≤n,则序号为i的结点的左孩子结点的序号为2i,如果2*i>n,则序号为i的结点无左孩子。
  • 如果2i+1≤n,则序号为i的结点的右孩子结点的序号为2i+1;如果2*i+1>n,则序号为i的结点无右孩子。
  • 若结点i序号为奇数且不等于1,则它的左兄弟序号为i-1
  • 若结点i的序号为偶数且不等于n,则他的右兄弟序号为i+1
  • 结点i所在层数(层次)为 ⌊ l o g 2 i ⌋ \lfloor log_2 i\rfloor log2i+1
    如果对二叉树的根节点从0开始编号,则i结点的父亲编号 ⌊ i / 2 ⌋ \lfloor i/2 \rfloor i/2,左孩子的编号为2i+1,右孩子的编号为2(i+1)

二叉树的数据结构

template<typename T>
class BSTree
{
public:
private:
// 定义BST树结点的类型
	struct BSTNode
	{
		BSTNode(T data = T())
			:_data(data)
			, _left(nullptr)
			, _right(nullptr)
		{}
		T _data;
		BSTNode *_left;
		BSTNode *_right;
	};

BSTNode *_root; // 指向树的根节点
}

二叉树的常用操作

已知前序和中序遍历结果,重构二叉树

// 已知一棵BST树的前序遍历结果pre数组,和中序遍历结果in数组,重建二叉树
	void rebuildBSTree(int pre[], int len1, int in[], int len2)
	{
		this->_root = rebuildBSTree(pre, 0, len1-1, in, 0, len2-1);
	}


BSTNode* rebuildBSTree(int pre[], int i, int j, int in[], int m, int n)
	{
		if (i > j || m > n)
		{
			return nullptr;
		}

		BSTNode *root = new BSTNode(pre[i]);
		for (int k = m; k <= n; ++k)
		{
			if (in[k]==pre[i]) // 中序遍历找到根节点了
			{
				root->_left = rebuildBSTree(pre, i+1, i+(k-m), in, m, k-1);
				root->_right = rebuildBSTree(pre, i+(k - m)+1, j, in, k+1, n);
				break;
			}
		}
		return root;
	}

判断是否是子树

// 判断参数tree是否是当前BST树的一颗子树,是返回true,否则返回false
	bool isChildTree(const BSTree<T> &tree)
	{
		if (_root == nullptr)
			return false;
		BSTNode *cur = _root;
		while (cur != nullptr)
		{
			if (tree._root->_data > cur->_data)
			{
				cur = cur->_right;
			}
			else if (tree._root->_data < cur->_data)
			{
				cur = cur->_left;
			}
			else
			{
				break;
			}
		}
		if (cur == nullptr)
			return false;

		return isChildTree(cur, tree._root);
	}



// 从father节点开始判断,是否全包含child的节点
	bool isChildTree(BSTNode *father, BSTNode *child)
	{
		if (father == nullptr && child == nullptr)
		{
			return true;
		}

		if (father == nullptr)
		{
			return false;
		}

		if (child == nullptr)
		{
			return true;
		}

		if (father->_data != child->_data)
		{
			return false;
		}

		return isChildTree(father->_left, child->_left)
			&& isChildTree(father->_right, child->_right);
	}

实现对BST树的镜像翻转


	void mirror()
	{
		mirror(_root);
	}
   
    
    void mirror(BSTNode *node)
	{
		if (node == nullptr)
			return;

		BSTNode *ptmp = node->_left;
		node->_left = node->_right;
		node->_right = ptmp;

		mirror(node->_left);
		mirror(node->_right);
	}

非递归实现找中序遍历的倒数第K个结点

  int  getLastKValue(int k)
	{
		static int n = number(_root) - k;
		if (_root == nullptr)
			return -1;

		stack<BSTNode*> s;
		BSTNode *cur = _root;
		while (!s.empty() || cur != nullptr)
		{
			if (cur != nullptr)
			{
				s.push(cur);
				cur = cur->_left;
			}
			else
			{
				BSTNode *top = s.top();
				s.pop();
				while ((n--) == 0)
				{
					return top->_data;
				}
				cur = top->_right;
			}
		}
	}

递归实现找中序遍历的倒数第K个结点


// 获取中序遍历倒数第k个节点的值
	int getLastKValue(int k) // LVR    RVL
	{
		int i = 0;
		BSTNode *p = getLastKValue(_root, k, i);
		if (p != nullptr)
		{
			return p->_data;
		}
		else
		{
			throw "no last k value, k is invalid!";
		}
	}

// LVR RVL 以node为根节点,找反向中序遍历的第K个节点
	BSTNode* getLastKValue(BSTNode *node, int k, int &i)
	{
		if (node == nullptr)
		{
			return nullptr;
		}

		BSTNode *p1 = getLastKValue(node->_right, k, i); // R
		if (p1 != nullptr)
		{
			return p1;
		}

		i++;
		if (k == i)
		{
			return node; // V
		}

		return getLastKValue(node->_left, k, i); // L
	}

找公共祖先结点



// 获取两个节点的最近公共祖先节点
	int getLCA(int val1, int val2)
	{
		BSTNode *p = getLCA(_root, val1, val2);
		if (p != nullptr)
		{
			return p->_data;
		}
		else
		{
			throw "no LCA node!";
		}
	}

// 以node为根节点,开始寻找val1和val2的LCA
	BSTNode* getLCA(BSTNode *node, int val1, int val2)
	{
		if (node == nullptr)
		{
			return nullptr;
		}
			
		if (val1 < node->_data && val2 < node->_data) 
		{
			return getLCA(node->_left, val1, val2);
		}
		else if (val1 > node->_data && val2 > node->_data)
		{
			return getLCA(node->_right, val1, val2);
		}
		else
		{
			return node;
		}
	}

判断二叉树是不是BST树


// 判断当前二叉树是不是一颗BST树
	bool isBSTree()
	{
		BSTNode *pre = nullptr;
		return isBSTree(_root, pre);
	}

// 以node为根节点,判断当前二叉树是不是BST树
	bool isBSTree(BSTNode *node, BSTNode *&pre)
	{
		if (node == nullptr)
		{
			return true;
		}

		if (!isBSTree(node->_left, pre))
		{
			return false;
		}
			
		if (pre != nullptr)
		{
			if (node->_data <= pre->_data)
			{
				return false;
			}
		}
		pre = node;
			
		return isBSTree(node->_right, pre);
	}

非递归实现在BST树查找指定的元素值val是否存在

	bool query(const T &val)
	{
		BSTNode *cur = _root;
		if (cur == nullptr)
		{
			return false;
		}

		while (cur != nullptr)
		{
			if (val == cur->_data)
			{
				return true;
			}
			else if (val < cur->_data)
			{
				cur = cur->_left;
			}
			else
			{
				cur = cur->_right;
			}
		}

		return false;
	}

递归实现在BST树查找指定的元素值val是否存在

BSTNode *  query(const T& val)
	{
		return query(_root, val);
	}

	BSTNode * query(BSTNode *node, int val)
	{
		if (node == nullptr)
		{
			return nullptr;
		}
		BSTNode *cur = node;
		if (cur->_data == val)
		{
			return cur;
		}
		else if (cur->_data < val)
		{
			return query(cur->_right, val);
		}
		else
		{
			return query(cur->_left, val);
		}
	}

非递归实现BST树的插入操作

	void noninsert(const T &val)
	{
		if (_root == nullptr)
		{
			_root = new BSTNode(val);
			return;
		}

		BSTNode *pre = nullptr;
		BSTNode *cur = _root;
		while (cur != nullptr)
		{
			pre = cur;
			if (val < cur->_data)
			{
				cur = cur->_left;
			}
			else if (val > cur->_data)
			{
				cur = cur->_right;
			}
			else
			{
				return;
			}
		}

		if (val < pre->_data)
		{
			pre->_left = new BSTNode(val);
		}
		else
		{
			pre->_right = new BSTNode(val);
		}
	}

递归实现BST树的插入操作


//递归实现BST树的插入操作
	void  insert(const  T &val)
	{
		_root = insert(_root, val);
	}
 
	BSTNode * insert(BSTNode *node, const T &val)
	{
		if (node == nullptr)
		{
			node = new BSTNode(val);
			return node;
		}

		if (val < node->_data)
		{
			node->_left = insert(node->_left, val);
		}
		else if (val > node->_data)
		{
			node->_right = insert(node->_right, val);
		}
		return node;
	}

非递归实现BST树的删除操作

BST树的删除操作,分为3种情况

  • 删除的结点没有孩子
  • 删除的结点只有一个孩子
  • 删除的结点有两个孩子

    主要思路是:用前驱结点或者后继结点替换当前待删除的结点

前驱结点当前结点左子树中元素最大的值所在的结点
后继结点当前结点右子树中元素最小的值所在的结点

步骤

  • 从根节点(_root)开始寻找值为val的结点,用一个指针(cur)指向它
  • 先判断是否满足情况3
  • 如果满足,需要找cur的前驱结点,用前驱结点的值把cur结点的值给覆盖掉,直接删前驱结点
  • 删除情况1和情况2

	void nonremove(const T &val)
	{
		// 1. 从_root开始寻找值为val的节点,cur指向它
		BSTNode *pre = nullptr;
		BSTNode *cur = _root;
		while (cur != nullptr)
		{
			if (val < cur->_data)
			{
				pre = cur;
				cur = cur->_left;
			}
			else if (val > cur->_data)
			{
				pre = cur;
				cur = cur->_right;
			}
			else
			{
				break;
			}
		}

		if (cur == nullptr)
			return;

		// 2. 先判断是否满足情况3,如果满足,需要找cur的前驱节点,用前驱把cur节点的值给覆盖掉,直接删前驱
		if (cur->_left != nullptr && cur->_right != nullptr)
		{
			BSTNode *old = cur;
			pre = cur;
			cur = cur->_left;
			while (cur->_right != nullptr)
			{
				pre = cur;
				cur = cur->_right;
			}
			old->_data = cur->_data;
		}
		// 3. 删除情况1和情况2   直接删除cur指针指向的节点就可以了
		BSTNode *child = cur->_left;
		if (child == nullptr)
		{
			child = cur->_right;
		}

		if (pre == nullptr) // 只有一个根节点是要被删除的结点
		{
			_root = child;
		}
		else
		{
			// 要把删除节点的孩子赋给cur父节点相应的地址域里面
			if (cur == pre->_left)
			{
				pre->_left = child;
			}
			else
			{
				pre->_right = child;
			}
		}
		delete cur;
	}

递归实现BST树的删除操作

BSTNode* remove(BSTNode *node, const T &val)
	{
		if (node == nullptr)
			return nullptr;

		if (node->_data > val)
		{
			node->_left = remove(node->_left, val);
		}
		else if (node->_data < val)
		{
			node->_right = remove(node->_right, val);
		}
		else
		{
			if (node->_left != nullptr && node->_right != nullptr)
			{
				BSTNode *pre = node->_left;
				while (pre->_right != nullptr)
				{
					pre = pre->_right;
				}
				node->_data = pre->_data;
				// 直接删除前驱
				node->_left = remove(node->_left, pre->_data);
			}
			else
			{
				if (node->_left != nullptr)
				{
					BSTNode *left = node->_left;
					delete node;
					return left;
				}
				else if (node->_right != nullptr)
				{
					BSTNode *right = node->_right;
					delete node;
					return right;
				}
				else
				{
					delete node;
					return nullptr;
				}
			}
		}
		return node;
	}

递归实现返回BST树所有结点的个数

   int number(BSTNode *node)
	{
		if (node == nullptr)
			return 0;
		return 1 + number(node->_left) + number(node->_right);
	}

递归实现返回BST树的层数


	// 返回以node为根节点的树的层数/高度
	int level(BSTNode *node)
	{
		if (node == nullptr)
		{
			return 0;
		}
		else
		{
			int left = level(node->_left);
			int right = level(node->_right);
			return left > right ? left + 1 : right + 1;
		}
	}

判断当前二叉树是不是BST树


// 判断当前二叉树是不是一颗BST树
	bool isBSTree()
	{
		BSTNode *pre = nullptr;
		return isBSTree(_root, pre);
	}

// 以node为根节点,判断当前二叉树是不是BST树
	bool isBSTree(BSTNode *node, BSTNode *&pre)
	{
		if (node == nullptr)
		{
			return true;
		}

		if (!isBSTree(node->_left, pre))
		{
			return false;
		}
			
		if (pre != nullptr)
		{
			if (node->_data < pre->_data)
			{
				return false;
			}
		}
		pre = node;
			
		return isBSTree(node->_right, pre);
	}

找满足区间[first,last]之间的元素

// 以node为根节点,中序遍历BST树,找满足区间[first,last]之间的元素
	void findAreaData(BSTNode *node, int first, int last, vector<int> &vec)
	{
		if (node == nullptr)
			return;

		findAreaData(node->_left, first, last, vec);

		if (node->_data > last)
		{
			return;
		}
		if (first <= node->_data && last >= node->_data)
		{
			vec.push_back(node->_data);
		}

		findAreaData(node->_right, first, last, vec);
	}

(非递归)实现BST树的遍历

非递归实现层序遍历

  • 如果_root为空,直接返回
  • 根节点入队(_root -> queue)
  • 循环环判断队列是否为空
  • 不为空取出队头元素,分别判断左右孩子是否为nullptr
  • 不为空就要依次入队
  • 然后打印队头元素,继续判断下一个队头元素
	void nonlevelOrder()
	{
		
		if (_root == nullptr)
			return;
		
		queue<BSTNode*> que;
		que.push(_root);

		 
		while (!que.empty())
		{
			BSTNode *front = que.front();
			cout << front->_data << " ";
			que.pop();
			if (front->_left != nullptr)
			{
				que.push(front->_left);
			}
			if (front->_right != nullptr)
			{
				que.push(front->_right);
			}
		}
	}

非递归实现前序遍历(解法1)

   void  nonfrontOrder()
	{
		BSTNode *cur = _root;
		if (cur == nullptr)
		{
			return;
		}
		stack<BSTNode *> stk;
		while (!(cur==nullptr&&stk.empty()))
		{
			while (cur != nullptr)
			{
				cout <<cur->_data << endl;//在入栈前访问
				stk.push(cur);
				cur = cur->_left;//让左孩子一直压栈
			}
			cur = stk.top();//左孩子处理完了
			stk.pop();
			cur = cur->_right;//处理右孩子
		}
	}

非递归实现前序遍历(解法2)

void nonpreOrder()
	{
		if (_root == nullptr)
			return;

		stack<BSTNode*> s;
		s.push(_root);

		while (!s.empty()) // VLR
		{
			BSTNode *top = s.top();
			s.pop();
			cout << top->_data << " "; // 打印V元素

			if (top->_right != nullptr) // 把右孩子先入栈
			{
				s.push(top->_right);
			}

			if (top->_left != nullptr) // 把左孩子后入栈,左孩子就在栈顶
			{
				s.push(top->_left);
			}
		}
		cout << endl;
	}

非递归实现中序遍历

void  nonmidOrder()
	{
		BSTNode *cur = _root;
		if (cur == nullptr)
		{
			return;
		}
		stack<BSTNode *> stk;
		while (!(cur == nullptr&&stk.empty()))
		{
			while (cur != nullptr)
			{
				
				stk.push(cur);
				cur = cur->_left;//让左孩子一直压栈
			}
			cur = stk.top();//左孩子处理完了
			stk.pop();
			cout << cur->_data << endl;
			cur = cur->_right;//处理右孩子
		}
	
	
	}

非递归实现后序遍历(解法1)

void nonbackOrder()
	{
		BSTNode *cur = _root;
		if (cur == nullptr)
		{
			return;
		}
		stack<BSTNode *>S1;
		stack<BSTNode *> S2;//用来存储最后需要打印的数据

		while (cur || !S1.empty())
		{
			while (cur)        //一直向右并将沿途节点访问(压入S2)后压入堆栈S1 
			{
				S2.push(cur);
				S1.push(cur);
				cur = cur->_right;
			}
			if (!S1.empty())
			{
				cur = S1.top();    //节点弹出堆栈
				S1.pop();
				cur = cur->_left;  //转向左子树
			}
		}
		while (!S2.empty())    //访问(打印)S2中元素
		{
			cur =S2.top();
			S2.pop();
			printf("%d\n",cur->_data);
		}
	}

非递归实现后序遍历(解法2)

// 非递归实现BST的后序遍历  LRV
	void nonpostOrder()
	{
		if (_root == nullptr)
			return;

		stack<BSTNode*> s1; // 辅助用的栈
		stack<BSTNode*> s2; // 存储后序遍历节点的栈
		s1.push(_root);

		while (!s1.empty())
		{
			BSTNode *top = s1.top();
			s1.pop();

			if (top->_left != nullptr)
			{
				s1.push(top->_left);
			}
			if (top->_right != nullptr)
			{
				s1.push(top->_right);
			}
			s2.push(top);
		}

		while (!s2.empty())
		{
			cout << s2.top()->_data << " ";
			s2.pop();
		}
		cout << endl;
	}

(递归)实现BST树的遍历

递归实现前序遍历

void frontOrder(BSTNode *node)
	{
		if (node == nullptr)
		{
			return;
		}

		cout << node->_data << endl;
		frontOrder(node->_left);
		frontOrder(node->_right);
	}

递归实现中序遍历

void midOrder(BSTNode *node)
	{
		if (node == nullptr)
		{
			return;
		}
		midOrder(node->_left);
		cout << node->_data << endl;
		midOrder(node->_right);
	}

递归实现后序遍历

void backOrder(BSTNode *node)
	{
		if (node == nullptr)
		{
			return;
		}
		backOrder(node->_left);
		backOrder(node->_right);
		cout << node->_data << endl;
	}

递归实现层序遍历


	void levelOrder()
	{
		cout << "递归实现层序遍历:";
		int l = level(_root);
		for (int i = 0; i < l; ++i)
		{
			levelOrder(_root, i);
		}
		cout << endl;
	}


    // 打印以node为根节点的树的层序遍历
	void levelOrder(BSTNode *node, int k) // 2
	{
		if (node != nullptr)
		{
			if (k == 0)
			{
				cout << node->_data << " ";
				return;
			}
			levelOrder(node->_left, k - 1);
			levelOrder(node->_right, k - 1);
		}
	}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值