二叉搜索树实现-c++

 二叉搜索树是比较常见的数据结构。可以说是所有的树结构中最基础的树结构。二叉搜索树最重要的特性是某结点左子树所有结点值小于该结点存放值,右子树所有结点值大于该结点存放值。

 这也是二叉“搜索”树名字由来。如果没有这个特性,倘若我们要搜索某个值,需要遍历所有结点。而借助这个特性,我们可以减少许多没有意义的搜索,极大提高搜索效率。

至于二叉搜索树的实现,有几个比较关键点。

1>前序遍历,中序遍历,后序遍历,分别有递归版本和迭代版本。

递归版本很好理解。迭代版本就是利用了栈(先进后出嘛),实际上就是模拟递归过程。

   层序遍历就很好理解,层层深入,利用队列(先进先出)。

void preOrder()//整棵树前序遍历
	{
		preOrder(root);
		cout << endl;
	}

	void preOrderNR()//前序遍历迭代版
	{
		if (root == nullptr) return;

		stack<Node<T>*> stk;
		stk.push(root);

		while (!stk.empty())
		{
			Node<T>* cur = stk.top();
			stk.pop();
			cout << cur->e << " ";
			if (cur->right) stk.push(cur->right);
			if (cur->left) stk.push(cur->left);
		}
		cout << endl;
	}

	void inOrder()//整棵树中序遍历
	{
		inOrder(root);
		cout << endl;
	}

	void inOrderNR()//中序遍历迭代版
	{
		stack<Node<T>*> stk;
		Node<T>* cur = root;

		while (cur || !stk.empty())
		{
			while (cur)
			{
				stk.push(cur);
				cur = cur->left;
			}

			if (!stk.empty())
			{
				cur = stk.top();
				stk.pop();
				cout << cur->e << " ";
				cur = cur->right;
			}
		}

		cout << endl;
	}

	void postOrder()//整棵树后序遍历
	{
		postOrder(root);
		cout << endl;
	}

	void postOrderNR()//后序遍历迭代版
	{
		Node<T>* cur = root;
		Node<T>* tem;
		stack<Node<T>*> stk;

		while (cur || !stk.empty())
		{
			while (cur)
			{
				stk.push(cur);
				cur = cur->left;
			}

			if (!stk.empty())
			{
				cur = stk.top();
				if (cur->right == nullptr || cur->right == tem)
				{
					cout << cur->e << " ";
					stk.pop();
					tem = cur;
					cur = nullptr;
				}
				else cur = cur->right;
			}
		}
		cout << endl;
	}


	void leverOrder()//层序遍历
	{
		if (root == nullptr) return;
		queue<Node<T>* > que;
		que.push(root);
		while (!que.empty())
		{
			Node<T>* cur = que.top();
			que.pop();
			cout << cur->e << " ";
			if (cur->left) que.push(cur->left);
			if (cur->right) que.push(cur->right);
		}
		cout << endl;
	}
void preOrder(Node<T>* node)//前序遍历递归版
	{
		if (node == nullptr) return;
		cout << node->e << " ";
		preOrder(node->left);
		preOrder(node->right);
	}

	void inOrder(Node<T>* node)//中序遍历递归版
	{
		if (node == nullptr) return;
		inOrder(node->left);
		cout << node->e << " ";
		inOrder(node->right);
	}

	void postOrder(Node<T>* cur)//后序遍历递归版
	{
		if (root == nullptr) return;
		postOrder(cur->left);
		postOrder(cur->right);
		cout << cur->e << " ";
	}

2>添加结点(add),这里我们重载了add函数。add(T e)是对外接口,而另一个add函数就是实现搜索插入过程。

Node<T>* add(Node<T> node, T e)//某个结点下添加元素
	{
		if (node == nullptr)
		{
			++size;
			return new Node<T>(e);
		}

		if (node->e > e)
		{
			node->left = new Node<T>(e);
		}
		else node->right = new Node<T>(e);

		return node;
	}

	void add(T e) //向整个树中添加某个元素
	{
		if (root == nullptr)
		{
			++size;
			root = new Node<T>(e);
		}
		add(root, e);
	}

3>查找最小结点和最大结点。同add操作一样,public和private分别重载。public中minmun(maxmun)调用private中min(max)找到最小(最大)结点指针。有同学可能疑惑为什么

要重载(上述add也是),其实原因在于,我们实现add和minmun,maxmun是对外的接口,可是如果我们要实现其功能,需要利用递归,可是仅仅凭public中这些函数的形参,根本无法实现递归,因为我使用public函数不可能传入具体哪个结点,比如增添一个值为e的结点,我们只会add(e),

正常人思路不会是add(root,e)。所以private中函数实际上才是public中这些函数的“真正实现”

T minmun()//返回树中最小值
	{
		assert(size > 0);
		return min(root)->e;
	}

	T maxmun()//返回树中最大值
	{
		assert(size > 0);
		return max(root)->e;
	}

	Node<T>* min(Node<T>* cur)//返回最小值结点
	{
		if (cur->left == nullptr) return cur;
		return min(cur->left);
	}

	Node<T>* max(Node<T>* cur)//返回最大值结点
	{
		if (cur->right == nullptr) return cur;
		return max(cur->right);
	}

4>删除(remove)操作。删除最小结点(removeMin)和删除最大结点(removeMax)和上述函数一样,需要借助private中函数实现功能。具体看代码。

T removeMin()//删除最小结点并返回最小值
	{
		T ret = minmun();
		root = removeMin(root);
		return ret;
	}

	T removeMax()//删除最大结点并返回最大值
	{
		T ret = maxmun();
		root = removeMax(root);
		return ret;
	}
Node<T>* removeMin(Node<T>* node)//删除以node为根结点子树的最小结点,并返回删除后剩下子树根节点
	{
		if (node->left == nullptr)
		{
			Node<T>* right_node = node->right;
			delete node;
			--size;
			return right_node;
		}
		node->left = removeMin(root->left);
		return node;
	}

	Node<T>* removeMax(Node<T>* node)//删除以node为根结点子树的最大结点,并返回删除后剩下子树根结点
	{
		if (node->right == nullptr)
		{
			Node<T>* left_node = node->left;
			delete node;
			--size;
			return left_node;
		}
		node->right = removeMax(node->right);
		return node;
	}

难理解的是remove(T e)函数(删除掉具体某个值)。前面递归部分很好理解。问题在于这个函数最后的一种情况,也就是当前遍历的这个结点node的e值正好等于这个值,并且左右儿子都有,那么这个删除操作比前面只有一个儿子情况麻烦一些。其实这里用两种方法,我们这里举其中一种。

我们要删除这个结点node,删除简单,问题是删除之后剩下的左右子树如何调整构成新的二叉搜索树。这时我们要利用二叉搜索树特性,左边永远小,右边永远大。那么这里我们可以找到node右边最小结点right_min作为删除node后新子树的根结点,这时node左边的子树此时照搬给right_min作为左二子(因为right_min是原来node右边,肯定比node左边所有结点大),然后将node->right删除掉right_min后剩下的子树作为right_min的右儿子(right_min是原来node右子树中最小的结点),满足了二叉搜索树特性,因此这种做法是可行的。

同理我们也可以让node左子树中最大的结点为新的根节点,也满足二叉树特性。

void remove(T e)//删除结点值为e的结点
	{
		root = remove(root, e);
	}


Node<T>* remove(Node<T>* node, T e)//删除以node为根节点子树中e值结点,并返回删除后剩余子树根节点
	{
		if (node == nullptr) return nullptr;
		if (e < node->e)
		{
			node->left = remove(node->left, e);
			return node;
		}
		else if (e > node->e)
		{
			node->right = remove(node->right, e);
			return node;
		}
		else
		{
			if (node->left == nullptr)
			{
				Node<T>* right_node = node->right;
				delete node;
				--size;
				return right_node;
			}
			else if (node->right == nullptr)
			{
				Node<T>* left_node = node->left;
				delete node;
				--size;
				return left_node;
			}
			else
			{
				Node<T>* right_min = new Node<T>(min(node->right)->e);
				right_min->right = removeMin(node->right);
				right_min->left = node->left;
				node->left = node->right = nullptr;
				delete node;
				--size;
				return right_min;
			}
		}
	}
};

完整代码如下,话都在酒。。。哦,是在代码里。 

#include<iostream>
#include<stack>
#include<queue>
#include<cassert>
using namespace std;

template<class T>
class Node
{
public:
	T e;
	Node<T>* left, right; //左右儿子

	Node(T e)
	{
		this->e = e;
		left = nullptr;
		right = nullptr;
	}
};

template<class T>
class BST
{
public:
	BST()//构造函数
	{
		root = nullptr;
		size = 0;
	}

	int get_size()//大小
	{
		return size;
	}

	bool is_empty()//判断是否为空
	{
		return size == 0;
	}

	Node<T>* add(Node<T> node, T e)//某个结点下添加元素
	{
		if (node == nullptr)
		{
			++size;
			return new Node<T>(e);
		}

		if (node->e > e)
		{
			node->left = new Node<T>(e);
		}
		else node->right = new Node<T>(e);

		return node;
	}

	void add(T e) //向整个树中添加某个元素
	{
		if (root == nullptr)
		{
			++size;
			root = new Node<T>(e);
		}
		add(root, e);
	}

	bool contains(T e)//整个树中是否包含某个元素
	{
		return contains(root, e);
	}

	void preOrder()//整棵树前序遍历
	{
		preOrder(root);
		cout << endl;
	}

	void preOrderNR()//前序遍历迭代版
	{
		if (root == nullptr) return;

		stack<Node<T>*> stk;
		stk.push(root);

		while (!stk.empty())
		{
			Node<T>* cur = stk.top();
			stk.pop();
			cout << cur->e << " ";
			if (cur->right) stk.push(cur->right);
			if (cur->left) stk.push(cur->left);
		}
		cout << endl;
	}

	void inOrder()//整棵树中序遍历
	{
		inOrder(root);
		cout << endl;
	}

	void inOrderNR()//中序遍历迭代版
	{
		stack<Node<T>*> stk;
		Node<T>* cur = root;

		while (cur || !stk.empty())
		{
			while (cur)
			{
				stk.push(cur);
				cur = cur->left;
			}

			if (!stk.empty())
			{
				cur = stk.top();
				stk.pop();
				cout << cur->e << " ";
				cur = cur->right;
			}
		}

		cout << endl;
	}

	void postOrder()//整棵树后序遍历
	{
		postOrder(root);
		cout << endl;
	}

	void postOrderNR()//后序遍历迭代版
	{
		Node<T>* cur = root;
		Node<T>* tem;
		stack<Node<T>*> stk;

		while (cur || !stk.empty())
		{
			while (cur)
			{
				stk.push(cur);
				cur = cur->left;
			}

			if (!stk.empty())
			{
				cur = stk.top();
				if (cur->right == nullptr || cur->right == tem)
				{
					cout << cur->e << " ";
					stk.pop();
					tem = cur;
					cur = nullptr;
				}
				else cur = cur->right;
			}
		}
		cout << endl;
	}


	void leverOrder()//层序遍历
	{
		if (root == nullptr) return;
		queue<Node<T>* > que;
		que.push(root);
		while (!que.empty())
		{
			Node<T>* cur = que.top();
			que.pop();
			cout << cur->e << " ";
			if (cur->left) que.push(cur->left);
			if (cur->right) que.push(cur->right);
		}
		cout << endl;
	}

	T minmun()//返回树中最小值
	{
		assert(size > 0);
		return min(root)->e;
	}

	T maxmun()//返回树中最大值
	{
		assert(size > 0);
		return max(root)->e;
	}

	T removeMin()//删除最小结点并返回最小值
	{
		T ret = minmun();
		root = removeMin(root);
		return ret;
	}

	T removeMax()//删除最大结点并返回最大值
	{
		T ret = maxmun();
		root = removeMax(root);
		return ret;
	}

	void remove(T e)//删除结点值为e的结点
	{
		root = remove(root,e);
	}
private:
	Node<T>* root;//根结点
	int size;//树的大小

	bool contains(Node<T>* node, T e)//实现public中contains功能
	{
		if (node == nullptr) return false;
		else if (node->e == e) return true;
		else if (node->e > e) return contains(node->left, e);
		else return contains(node->right, e);
	}

	void preOrder(Node<T>* node)//前序遍历递归版
	{
		if (node == nullptr) return;
		cout << node->e << " ";
		preOrder(node->left);
		preOrder(node->right);
	}

	void inOrder(Node<T>* node)//中序遍历递归版
	{
		if (node == nullptr) return;
		inOrder(node->left);
		cout << node->e <<" ";
		inOrder(node->right);
	}

	void postOrder(Node<T>* cur)//后序遍历递归版
	{
		if (root == nullptr) return;
		postOrder(cur->left);
		postOrder(cur->right);
		cout << cur->e << " ";
	}


	Node<T>* min(Node<T>* cur)//返回最小值结点
	{
		if (cur->left == nullptr) return cur;
		return min(cur->left);
	}

	Node<T>* max(Node<T>* cur)//返回最大值结点
	{
		if (cur->right == nullptr) return cur;
		return max(cur->right);
	}

	Node<T>* removeMin(Node<T>* node)//删除以node为根结点子树的最小结点,并返回删除后剩下子树根节点
	{
		if (node->left == nullptr)
		{
			Node<T>* right_node = node->right;
			delete node;
			--size;
			return right_node;
		}
		node->left = removeMin(root->left);
		return node;
	}

	Node<T>* removeMax(Node<T>* node)//删除以node为根结点子树的最大结点,并返回删除后剩下子树根结点
	{
		if (node->right == nullptr)
		{
			Node<T>* left_node = node->left;
			delete node;
			--size;
			return left_node;
		}
		node->right = removeMax(node->right);
		return node;
	}

	Node<T>* remove(Node<T>* node, T e)//删除以node为根节点子树中e值结点,并返回删除后剩余子树根节点
	{
		if (node == nullptr) return nullptr;
		if (e < node->e)
		{
			node->left = remove(node->left, e);
			return node;
		}
		else if (e > node->e)
		{
			node->right = remove(node->right, e);
			return node;
		}
		else
		{
			if (node->left == nullptr)
			{
				Node<T>* right_node = node->right;
				delete node;
				--size;
				return right_node;
			}
			else if (node->right == nullptr)
			{
				Node<T>* left_node = node->left;
				delete node;
				--size;
				return left_node;
			}
			else
			{
				Node<T>* right_min = new Node<T>(min(node->right)->e);
				right_min->right = removeMin(node->right);
				right_min->left = node->left;
				node->left = node->right = nullptr;
				delete node;
				--size;
				return right_min;
			}
		}
	}
};

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
二叉搜索树的删除操作可以分为以下几步: 1. 首先找到要删除的节点,可以使用二叉搜索树的查找方法,从根节点开始递归查找。 2. 如果要删除的节点是叶子节点,直接删除即可。 3. 如果要删除的节点只有一个子节点,将该子节点接替要删除的节点即可。 4. 如果要删除的节点有两个子节点,需要找到要删除节点的中序遍历后继节点(也就是比要删除的节点大的最小节点),将其值复制到要删除的节点中,然后再将中序遍历后继节点删除。 以下是一个示例代码实现: ```python class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right class Solution: def deleteNode(self, root: TreeNode, key: int) -> TreeNode: if not root: return None # 找到要删除的节点 if key < root.val: root.left = self.deleteNode(root.left, key) elif key > root.val: root.right = self.deleteNode(root.right, key) else: # 叶子节点或只有一个子节点 if not root.left: return root.right elif not root.right: return root.left # 有两个子节点 else: successor = root.right while successor.left: successor = successor.left root.val = successor.val root.right = self.deleteNode(root.right, successor.val) return root ``` 在这个实现中,我们首先使用递归找到要删除的节点,然后根据节点的情况进行删除操作。如果节点是叶子节点或只有一个子节点,直接将其删除或将其子节点接到父节点上。如果节点有两个子节点,找到中序遍历后继节点,将其值复制到要删除的节点上,然后再将中序遍历后继节点删除。最后返回删除操作后的根节点即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值