【C++】搜索二叉树

提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 一、搜索二叉树概念
  • 二、搜索二叉树的操作
    • 1.插入
    • 2. 查找
    • 3. 中序遍历
    • 4. 删除
  • 三、默认成员函数
    • 1.析构函数
    • 2.拷贝构造
    • 3. 赋值运算符重载
  • 四、完整代码


一、搜索二叉树概念

搜索二叉树 也叫做二叉排序树,它要么是一棵空树,要么具有以下性质:
(1)若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
(2)若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
(3)它的左右子树也分别为二叉搜索树

如下就是搜索二叉树,对于任何一个节点,它的左子树的所有节点值都比它小,它的右子树的所有节点值都比它大:

int a[] = {9,6,15,4,13,5,1,20,8,27};

【C++】搜索二叉树_第1张图片

总结:在左子树值比根小,右子树值比根大。 当树走中序遍历时,序列都是有序的。

搜索二叉树的结构定义:

//定义树的结点
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)
	{}
 
private:
	Node* _root;//根
};

提示:以下是本篇文章正文内容,下面案例可供参考

二、搜索二叉树的操作

1.插入

插入节点分两步:

(1)找位置

    ①key比当前节点值大,向右走

    ②key比当前节点值小,向左走

    ③key等于当前节点值,该节点值已经存在,插入失败

(2)插入

    ①key比父亲节点值小就插入父亲左子树

    ②key比父亲节点值大就插入父亲右子树

由于插入后,要将节点链接到树中,因此要定义parent节点,用来链接新节点:
【C++】搜索二叉树_第2张图片

bool Insert(const K& key)
	{
		//空树 -》 直接插入
		if (_root == nullptr)
		{
			_root = new Node(key);
		}

		//寻找插入位置
		Node* cur = _root;
		Node* parent = cur;
		while (cur)
		{
			if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			//搜索二叉树中不允许出现相同结点
			else
			{
				return false;
			}
		}
		//找到了插入节点的位置了-》判断插入节点与parent->_key的大小,判断插入到左子树还是右子树
		if (parent->_key > key)
		{
			parent->_left = new Node(key);
		}
		else
		{
			parent->_right = new Node(key);
		}
		return true;
	}

	//递归插入 形成二叉树
bool _InsertR(Node*& _root, const K& key)
	{
		//说明找到插入节点的位置了 / 树为NULL
		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;
	}

2. 查找

查找比较简单:

    ①key比当前节点值大,向右走

    ②key比当前节点值小,向左走

    ③key等于当前节点值,找到了

【C++】搜索二叉树_第3张图片

//查找 迭代
	Node* Find(const K& key)
	{
		Node* cur = _root;
		while (cur)
		{
			if (cur->_key > key)
			{
				cur = cur->_left;
			}
			else if (cur->_key < key)
			{
				cur = cur->_right;
			}
			else
				return cur;
		}
		return cur;
	}


//查找递归版本
	Node* _FindR(Node* _root, const K& key)
	{
		if (_root == nullptr) return _root;
		if (_root->_key > key) return _FindR(_root->_left, key);
		else if(_root->_key < key) return _FindR(_root->_right, key);
		else return _root;
	}

3. 中序遍历

由于根节点的访问限定符是私有的,那么在main函数中要终须遍历一棵树时,就无法将二叉搜索树的对象根节点传给中序遍历,因为类外面访问不到私有成员。

因此可以这样考虑:这个搜索二叉树对象是有根节点的,可以考虑在里面套一层,给套在里面的函数传参_root ,去递归调用自己:

	//内层函数使用_root
    void _Inorder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		_Inorder(root->_left);//递归调用自己
		cout << root->_key << " ";
		_Inorder(root->_right);//递归调用自己
	}
 
	//先调不传参数的InOrder
	void InOrder()
	{
		//把_root传给子函数,让子函数去使用_root
		_InOrder(_root);
		cout << endl;
	}

4. 删除

(1)找位置

    ①key比当前节点值大,向右走

    ②key比当前节点值小,向左走

    ③key等于当前节点值,找到了,准备删除

(2)删除,有两种删除方法:非递归和递归

非递归删除:

①该节点没有孩子,即该节点是叶子节点,删除节点后把父亲指向自己的指针置空

【C++】搜索二叉树_第4张图片

②该节点有一个孩子,就把该节点的孩子节点的链接给该节点的父亲,顶替自己的位置,①可以当成②的特殊情况
【C++】搜索二叉树_第5张图片
③该节点有两个孩子,找比它自己的左孩子大,比它自己的右孩子小的节点替换它(也就是拿它的左子树的最大节点或右子树的最小节点替换它),替换之后,该节点就只有一个孩子或没有孩子了,就变成①或②了。
【C++】搜索二叉树_第6张图片

//删除的非递归版本
	bool Erase(const K& key)
	{
		Node* cur = _root;
		Node* parent = nullptr;
		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;
					}
					else
					{
						if (parent->_left == cur)
						{
							parent->_left = cur->_right;
						}
						else
						{
							parent->_right = cur->_right;
						}
					}
					delete cur;
				}
				//删除结点的右子树为空
				else if (cur->_right == nullptr)
				{
					if (cur == _root)
					{
						_root = cur->_left;
					}
					else
					{
						if (parent->_left == cur)
						{
							parent->_left = cur->_left;
						}
						else
						{
							parent->_right = cur->_right;
						}
					}
					delete cur;
				}
				//删除节点的左右子树都不为空
				else
				{
					//寻找右子树的最小结点 最左
					Node* MinRightNode = cur->_right;
					Node* MinParentNode = cur;
					while (MinRightNode->_left)
					{
						MinParentNode = MinRightNode;
						MinRightNode = MinRightNode->_left;
					}
					//找到了右子树的最小结点
					swap(MinRightNode->_key, cur->_key);
					if (MinParentNode->_left == MinRightNode)
					{
						MinParentNode->_left = MinRightNode->_right;
					}
					else
					{
						MinParentNode->_right = MinRightNode->_right;
					}
					delete MinRightNode;
				}
				return true;
			}
		}
		return false;
	}

//递归删除
	bool _EraseR(Node*&_root, const K& key)
	{
		if (_root == nullptr)
			return false;
		if (key < _root->_key)
		{
			return _EraseR(_root->_left, key);
		}
		else if (_root->_key < key)
		{
			return _EraseR(_root->_right, key);
		}
		else
		{
			//删除
			// 左子树为空 
			if (_root->_left == nullptr)
			{
				Node* del = _root;
				_root = _root->_right;
				delete del;
			}
			//右子树为空
			else if (_root->_right == nullptr)
			{
				Node* del = _root;
				_root = _root->_left;
				delete del;
			}
			//左右子树都不为空
			else
			{
				//寻找右子树的最小结点 最左
				Node* MinRightNode = _root->_right;
				Node* MinParentNode = _root;
				while (MinRightNode->_left)
				{
					MinParentNode = MinRightNode;
					MinRightNode = MinRightNode->_left;
				}
				//找到了右子树的最小结点
				swap(MinRightNode->_key, _root->_key);
				if (MinParentNode->_left == MinRightNode)
				{
					MinParentNode->_left = MinRightNode->_right;
				}
				else
				{
					MinParentNode->_right = MinRightNode->_right;
				}
				delete MinRightNode;
			}
			return true;
		}
	}

三、默认成员函数

1.析构函数

递归调用子函数去析构

	~BSTree()
	{
		Destory(_root);
		_root = nullptr;
	}
	
void Destory(Node* _root)
	{
		if (_root == nullptr) return;
		Destory(_root->_left);
		Destory(_root->_right);
		delete _root;
	}

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

2.拷贝构造

拷贝构造利用递归调用子函数不断拷贝节点:

	//拷贝构造
	BSTree(const BSTree<K>& t)
	{
		_root = t.copy(t._root);
	}

在子函数处:

	Node* _copy(Node* root)
	{
		if (root == nullptr)//如果根为空,直接返回
		{
			return;
		}
 
		Node* copyNode = new Node(root->_key);//创建根节点
		copyNode->_left = _copy(root->_left);//递归拷贝左子树节点
		copyNode->_right = _copy(root->_right);//递归拷贝右子树节点
		
		return copyNode;//返回根
	}

3. 赋值运算符重载

使用节点互换的逻辑

	BSTree<K>& operator=(BSTree<K> t)  //t这里调用的拷贝构造-》深拷贝
	{
		swap(_root, t._root);
		Destory(t._root);
		t._root = nullptr;
		return *this;
	}

四、完整代码

//  .h  文件

#pragma once
#include 
using namespace std;
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() = default;

		
	//插入 形成搜索二叉树  迭代版本
	bool Insert(const K& key)
	{
		//空树 -》 直接插入
		if (_root == nullptr)
		{
			_root = new Node(key);
		}

		//寻找插入位置
		Node* cur = _root;
		Node* parent = cur;
		while (cur)
		{
			if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			//搜索二叉树中不允许出现相同结点
			else
			{
				return false;
			}
		}
		//找到了插入节点的位置了-》判断插入节点与parent->_key的大小,判断插入到左子树还是右子树
		if (parent->_key > key)
		{
			parent->_left = new Node(key);
		}
		else
		{
			parent->_right = new Node(key);
		}
		return true;
	}

	//递归插入 形成二叉树
	bool InsertR(const K& key)
	{
		return _InsertR(_root, key);
	}

	bool Erase(const K& key)
	{
		Node* cur = _root;
		Node* parent = nullptr;
		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;
					}
					else
					{
						if (parent->_left == cur)
						{
							parent->_left = cur->_right;
						}
						else
						{
							parent->_right = cur->_right;
						}
					}
					delete cur;
				}
				//删除结点的右子树为空
				else if (cur->_right == nullptr)
				{
					if (cur == _root)
					{
						_root = cur->_left;
					}
					else
					{
						if (parent->_left == cur)
						{
							parent->_left = cur->_left;
						}
						else
						{
							parent->_right = cur->_right;
						}
					}
					delete cur;
				}
				//删除节点的左右子树都不为空
				else
				{
					//寻找右子树的最小结点 最左
					Node* MinRightNode = cur->_right;
					Node* MinParentNode = cur;
					while (MinRightNode->_left)
					{
						MinParentNode = MinRightNode;
						MinRightNode = MinRightNode->_left;
					}
					//找到了右子树的最小结点
					swap(MinRightNode->_key, cur->_key);
					if (MinParentNode->_left == MinRightNode)
					{
						MinParentNode->_left = MinRightNode->_right;
					}
					else
					{
						MinParentNode->_right = MinRightNode->_right;
					}
					delete MinRightNode;
				}
				return true;
			}
		}
		return false;
	}

	//递归删除
	bool EraseR(const K& key)
	{
		return _EraseR(_root, key);
	}

	//查找 迭代
	Node* Find(const K& key)
	{
		Node* cur = _root;
		while (cur)
		{
			if (cur->_key > key)
			{
				cur = cur->_left;
			}
			else if (cur->_key < key)
			{
				cur = cur->_right;
			}
			else
				return cur;
		}
		return cur;
	}

	//查找->递归版本
	Node* FindR(const K& key)
	{
		return _FindR(_root, key);
	}
	//中序打印
	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}

	BSTree(const BSTree<K>& t)
	{
		_root = Copy(t._root);
	}

	~BSTree()
	{
		Destory(_root);
		_root = nullptr;
	}
	BSTree<K>& operator=(BSTree<K> t)
	{
		swap(_root, t._root);
		Destory(t._root);
		t._root = nullptr;
		return *this;
	}

private:
	//直接给缺省值,调用BSTree默认构造就不用初始化了
	Node* _root = nullptr;

	Node* Copy(const Node* _root)
	{
		if (_root == nullptr) return nullptr;
		//拷贝根节点  左子树  右子树
		Node* newnode = new Node(_root->_key);
		newnode->_left = Copy(_root->_left);
		newnode->_right = Copy(_root->_right);
		return newnode;
	}

	void Destory(Node* _root)
	{
		if (_root == nullptr) return;
		Destory(_root->_left);
		Destory(_root->_right);
		delete _root;
	}

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

	//递归插入  !!!Node*& _root 就表示当前节点的引用,我直接让_root直接等于new Node(key),直接链接
	bool _InsertR(Node*& _root, const K& key)
	{
		//说明找到插入节点的位置了 / 树为NULL
		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 (key < _root->_key)
		{
			return _EraseR(_root->_left, key);
		}
		else if (_root->_key < key)
		{
			return _EraseR(_root->_right, key);
		}
		else
		{
			//删除
			// 左子树为空 
			if (_root->_left == nullptr)
			{
				Node* del = _root;
				_root = _root->_right;
				delete del;
			}
			//右子树为空
			else if (_root->_right == nullptr)
			{
				Node* del = _root;
				_root = _root->_left;
				delete del;
			}
			//左右子树都不为空
			else
			{
				//寻找右子树的最小结点 最左
				Node* MinRightNode = _root->_right;
				Node* MinParentNode = _root;
				while (MinRightNode->_left)
				{
					MinParentNode = MinRightNode;
					MinRightNode = MinRightNode->_left;
				}
				//找到了右子树的最小结点
				swap(MinRightNode->_key, _root->_key);
				if (MinParentNode->_left == MinRightNode)
				{
					MinParentNode->_left = MinRightNode->_right;
				}
				else
				{
					MinParentNode->_right = MinRightNode->_right;
				}
				delete MinRightNode;
			}
			return true;
		}
	}


	//查找递归版本
	Node* _FindR(Node* _root, const K& key)
	{
		if (_root == nullptr) return _root;
		if (_root->_key > key) return _FindR(_root->_left, key);
		else if(_root->_key < key) return _FindR(_root->_right, key);
		else return _root;
	}
};


//  .cpp 文件

#include"BinarySearchTree.h"

int main()
{
	BSTree<int> root;
	int Tree[] = { 7,2,4,6,3,1,5};
	for (int i = 0; i < (sizeof(Tree) / sizeof(Tree[0])); i++)
	{
		root.InsertR(Tree[i]);
	}
	root.InOrder();

	BSTree<int> root1 = root;
	root1.InOrder();

}

你可能感兴趣的:(C++,c++)