数据结构——实现一个二叉查找树(BST)

文章目录

  • 1.BST的性质:
  • 2.BST的遍历
  • 3.BST的基本运算、方法
    • 3.1插入
    • 3.2查找
      • 3.2.1查找之迭代法
      • 3.2.2查找之递归法
    • 3.3 获取BST的最大结点和最小结点
    • 3.4 删除
    • 3.5 遍历
  • 4.完整代码及测试

BST(Binary Search Tree):二叉查找树,也叫二叉搜索树,或称二叉排序树Binary Sort Tree

1.BST的性质:

  • 每一个元素都有一个键值,并且键值不允许重复
  • 左子树的所有节点的键值都小于根结点
  • 右子树的所有节点的键值都大于根结点
  • 左右子树都是一个BST树

2.BST的遍历

BST是一种特殊的二叉树,它的遍历方法和二叉树相同,分为前序遍历、中序遍历和后序遍历,这3种遍历的实现(递归和迭代)我在前面的文章已经介绍过了,有兴趣可以参考一下。
二叉树的迭代法前序遍历的两种方法
二叉树的迭代法后序、中序遍历
二叉树的非递归(迭代)统一实现“前中后序遍历”详解
二叉树的层序遍历

3.BST的基本运算、方法

定义好3个结构、类:

  • struct Element{}:BST的节点的元素结构
  • class BstNode:BST的节点类
  • class Bst:BST类
/******************二叉查找树节点键值结构************************/
template <typename Type>
struct Element
{
	friend class BstNode<Type>;
	friend class Bst<Type>;

public:
	Element(){}
	Element(Type _key):key(_key){}
//private:
	Type key;//键值
	//可以添加更多数据
};

/******************二叉查找树节点类************************/
template <typename Type>
class BstNode
{
	friend class Bst<Type>;
public:
	BstNode():leftChild(nullptr), rightChild(nullptr){};
	BstNode(Element<Type> _content) :leftChild(nullptr), rightChild(nullptr)
	{
		content.key = _content.key;
	};



//private:
	Element<Type> content;
	BstNode<Type> *leftChild;
	BstNode<Type> *rightChild;
};
/******************二叉查找树类************************/
template <typename Type>
class Bst
{
public:
	Bst(BstNode<Type> *_root = nullptr) :root(_root){}

	void Insert(const Element<Type>&  _data);//插入

	BstNode<Type>* Search(const Element<Type>&  _data);//递归查找
	BstNode<Type>* Search(BstNode<Type>* node, const Element<Type>&  _data);
	BstNode<Type>* IterSearch(const Element<Type>&  _data);//迭代查找

	BstNode<Type>* FindMax();//查找子树的最大节点
	BstNode<Type>* FindMax(BstNode<Type>* node);
	BstNode<Type>* FindMin();//查找子树的最小节点
	BstNode<Type>* FindMin(BstNode<Type>* node);

	void Delete(const Element<Type>&  _data);//删除

	void InOrder();//中序遍历
	void InOrder(BstNode<Type>* node);

	void LevelOrder();//层序遍历
	void LevelOrder(BstNode<Type>* node);

private:
	BstNode<Type>* FindParent(BstNode<Type>* node);

	BstNode<Type> *root;
};

3.1插入

  • 若BST为空,则插入结点做为根节点;
  • 若BST不空,插入规则为:比节点键值小,插入在节点的左子树;比节点键值大,插入在节点的右子树

代码中均有详细注释,如下:

template <typename Type>
void Bst<Type>::Insert(const Element<Type>& _data)
{
	BstNode<Type> *newNode = new BstNode<Type>(_data);

	BstNode<Type> *cur = root;
	BstNode<Type> *tmp = root;

	//若bst树为空,则插入的节点就是根节点
	if (cur == nullptr) 
		root = newNode;
	//若bst树不空
	else{
		//1.找到连接newNode的父节点
		while (cur){
			tmp = cur;//tmp就是保存newNode的父节点

			if (newNode->content.key < cur->content.key){
				cur = cur->leftChild;
			}
			else if(newNode->content.key > cur->content.key){
				cur = cur->rightChild;
			}
			else{
				throw "Error";
			}
		}
		//2.确定newNode作为左节点还是右节点
		if (newNode->content.key < tmp->content.key){
			tmp->leftChild = newNode;
		}
		else if (newNode->content.key > tmp->content.key){
			tmp->rightChild = newNode;
		}
		else{ ; }
	}
}

3.2查找

我在这里给出递归和迭代两种方法:

3.2.1查找之迭代法

代码如下:

template <typename Type>
BstNode<Type>* Bst<Type>::IterSearch(const Element<Type>&  _data)
{
	BstNode<Type> *cur = root;
	while (cur){
		if (cur->content.key == _data.key)
			return cur;
		else if (_data.key < cur->content.key)
			cur = cur->leftChild;
		else if (_data.key > cur->content.key)
			cur = cur->rightChild; 
		else{}
	}
	return nullptr;
}

3.2.2查找之递归法

递归法需要用到重载。一个参数的Search函数是给类外部调用;由于使用递归调用,所以重载Search函数,增加一个表示节点类的参数。两个参数的Search函数应该作为类内部的私有成员函数。

BstNode<Type>* Search(const Element<Type>&  _data);//递归查找
BstNode<Type>* Search(BstNode<Type>* node, const Element<Type>&  _data);

代码如下:

template <typename Type>
BstNode<Type>* Bst<Type>::Search(const Element<Type>&  _data)
{
	return Search(root,_data);
}
template <typename Type>
BstNode<Type>* Bst<Type>::Search(BstNode<Type>* node, const Element<Type>&  _data)
{
	if (node == nullptr)
		return nullptr;

	if (_data.key < node->content.key)
		return Search(node->leftChild,_data);
	else if (_data.key > node->content.key)
		return Search(node->rightChild, _data);
	else 
		return node;
}

3.3 获取BST的最大结点和最小结点

FinMax()函数和FindMin()函数都重载了。原因是对外部而言,只需提供无参的函数,返回BST的最大值和最小值节点即可,但是对我们实现功能,是必须输入节点参数的。

BstNode<Type>* FindMax();//查找子树的最大节点
BstNode<Type>* FindMax(BstNode<Type>* node);
BstNode<Type>* FindMin();//查找子树的最小节点
BstNode<Type>* FindMin(BstNode<Type>* node);

查找最大值节点FinMax(),注意,一颗BST的最大值节点永远是在树的最右边

template <typename Type>
BstNode<Type>* Bst<Type>::FindMax()
{
	return FindMax(root);
}
template <typename Type>
BstNode<Type>* Bst<Type>::FindMax(BstNode<Type>* node)
{
	BstNode<Type> *cur = node;

	if (!cur) return nullptr;//node为空,直接返回

	while (cur->rightChild)
		cur = cur->rightChild;

	return cur;
}

查找最大值节点FinMin(),注意,一颗BST的最小值节点永远是在树的最左边

template <typename Type>
BstNode<Type>* Bst<Type>::FindMin()
{
	return FindMin(root);
}
template <typename Type>
BstNode<Type>* Bst<Type>::FindMin(BstNode<Type>* node)
{
	BstNode<Type> *cur = node;

	if (!cur) return nullptr;//node为空,直接返回

	while (cur->leftChild)
		cur = cur->leftChild;

	return cur;
}

3.4 删除

由于删除操作较为复杂,我在数据结构——详解二叉查找树(BST)的删除操作单独详细的描述了删除的操作,所以我在这里直接贴出代码:

template <typename Type>
void Bst<Type>::Delete(const Element<Type>&  _data)
{
	BstNode<Type> *deleteNode = nullptr;
	BstNode<Type> *deleteNodeParent = nullptr;

	BstNode<Type> *minNode = nullptr;
	BstNode<Type> *maxNode = nullptr;

	deleteNode = Search(_data);
	if (!deleteNode) return;//deleteNode为空,表明BST中没有元素为_data的节点,直接返回
	
	if (deleteNode->leftChild){//deleteNode有左子树,得到deleteNode左子树的最大值节点
		maxNode = FindMax(deleteNode->leftChild);
	}
	if (deleteNode->rightChild){//deleteNode有右子树,得到deleteNode右子树的最小值节点
		minNode = FindMin(deleteNode->rightChild);
	}

	deleteNodeParent = FindParent(deleteNode);//找到deleteNode节点的父节点
	//maxNode和minNode的节点为空,表明deleteNode是一个叶子节点
	if (!maxNode && !minNode){
		if (deleteNodeParent->leftChild == deleteNode)
			deleteNodeParent->leftChild = nullptr;
		else
			deleteNodeParent->rightChild = nullptr;
		
		delete deleteNode;
	}
	//表明deleteNode最少有一个子树不空
	else{

		//1.将tmp节点的父节点和tmp的子节点连接
		BstNode<Type> *tmp = (maxNode == nullptr) ? minNode : maxNode;
		BstNode<Type> * tmpParent = FindParent(tmp);
		if (tmp->leftChild){//左孩子不空,右孩子必空.此情况对应的是 maxNode
			if (tmpParent->leftChild == tmp)//tmp是左孩子
				tmpParent->leftChild = tmp->leftChild;
			else
				tmpParent->rightChild = tmp->leftChild;
		}
		else{//右孩不空,左孩子必空,此情况对应的是 minNode
			if (tmpParent->leftChild == tmp)
				tmpParent->leftChild = tmp->rightChild;
			else
				tmpParent->rightChild = tmp->rightChild;
		}

		//2.将tmp节点和deleteNode的父节点连接
		if (deleteNodeParent == nullptr)
			root = tmp;
		else{

			if (tmp->content.key < deleteNodeParent->content.key)
				deleteNodeParent->leftChild = tmp;
			else
				deleteNodeParent->rightChild = tmp;
		}
		//3.将tmp节点的左右孩子连接上deleteNode的左右孩子
		tmp->leftChild = deleteNode->leftChild;
		tmp->rightChild = deleteNode->rightChild;

		delete deleteNode;
	}
}

查找父节点的私有成员函数:

template <typename Type>
BstNode<Type>* Bst<Type>::FindParent(BstNode<Type>* node)
{
	//node = root.表明node无父节点
	if (root == node)
		return nullptr;

	BstNode<Type>* cur = root;

	while (cur && root){
		//返回父节点
		if (cur->leftChild == node || cur->rightChild == node)
			return cur;

		//cur节点不是node的父节点,根据key确定从cur的左子树找还是右子树找
		if (node->content.key < cur->content.key)
			cur = cur->leftChild;
		else
			cur = cur->rightChild;
	}
	return nullptr;
}

3.5 遍历

前、中、后序遍历和层序遍历在前面文章中均有详细的讲解,本文不做探讨。下面直接给出前中序遍历和层序遍历以便测试:

/******************中序遍历InOrder************************/
template <typename Type>
void Bst<Type>::InOrder()
{
	InOrder(root);
}
template <typename Type>
void Bst<Type>::InOrder(BstNode<Type>* node)
{
	if (node == nullptr)
		return;

	InOrder(node->leftChild);
	std::cout << node->content.key << std::endl;
	InOrder(node->rightChild);
}
/******************层序遍历InOrder************************/
template <typename Type>
void Bst<Type>::LevelOrder()
{
	LevelOrder(root);
}
template <typename Type>
void Bst<Type>::LevelOrder(BstNode<Type>* node)
{
	queue<BstNode<Type>*> q;
	q.push(node);

	while (!q.empty()){
		int size = q.size();

		std::cout << "[";
		for (int i = 0; i < size; i++){
			BstNode<Type>* tmp = q.front();
			q.pop();

			std::cout << tmp->content.key << " ";
			
			if (tmp->leftChild) q.push(tmp->leftChild);
			if (tmp->rightChild) q.push(tmp->rightChild);
		}
		std::cout <<"]" <<std::endl;
	}
}

4.完整代码及测试

Bst.h如下:

#ifndef _BST_H
#define _BST_H

#include 

template <typename Type>
class BstNode;

template <typename Type>
class Bst;


/******************二叉查找树节点键值结构************************/
template <typename Type>
struct Element
{
	friend class BstNode<Type>;
	friend class Bst<Type>;

public:
	Element(){}
	Element(Type _key):key(_key){}
//private:
	Type key;//键值
	//可以添加更多数据
};

/******************二叉查找树节点类************************/
template <typename Type>
class BstNode
{
	friend class Bst<Type>;
public:
	BstNode():leftChild(nullptr), rightChild(nullptr){};
	BstNode(Element<Type> _content) :leftChild(nullptr), rightChild(nullptr)
	{
		content.key = _content.key;
	};



//private:
	Element<Type> content;
	BstNode<Type> *leftChild;
	BstNode<Type> *rightChild;
};
/******************二叉查找树类************************/
template <typename Type>
class Bst
{
public:
	Bst(BstNode<Type> *_root = nullptr) :root(_root){}

	void Insert(const Element<Type>&  _data);//插入

	BstNode<Type>* Search(const Element<Type>&  _data);//递归查找
	BstNode<Type>* Search(BstNode<Type>* node, const Element<Type>&  _data);
	BstNode<Type>* IterSearch(const Element<Type>&  _data);//迭代查找

	BstNode<Type>* FindMax();//查找子树的最大节点
	BstNode<Type>* FindMax(BstNode<Type>* node);
	BstNode<Type>* FindMin();//查找子树的最小节点
	BstNode<Type>* FindMin(BstNode<Type>* node);

	void Delete(const Element<Type>&  _data);//删除

	void InOrder();//中序遍历
	void InOrder(BstNode<Type>* node);

	void LevelOrder();//层序遍历
	void LevelOrder(BstNode<Type>* node);

private:
	BstNode<Type>* FindParent(BstNode<Type>* node);

	BstNode<Type> *root;
};

/******************二叉查找树成员函数************************/

/******************插入Insert************************/
template <typename Type>
void Bst<Type>::Insert(const Element<Type>& _data)
{
	BstNode<Type> *newNode = new BstNode<Type>(_data);

	BstNode<Type> *cur = root;
	BstNode<Type> *tmp = root;

	//若bst树为空,则插入的节点就是根节点
	if (cur == nullptr) 
		root = newNode;
	//若bst树不空
	else{
		//1.找到连接newNode的父节点
		while (cur){
			tmp = cur;//tmp就是保存newNode的父节点

			if (newNode->content.key < cur->content.key){
				cur = cur->leftChild;
			}
			else if(newNode->content.key > cur->content.key){
				cur = cur->rightChild;
			}
			else{
				throw "Error";
			}
		}
		//2.确定newNode作为左节点还是右节点
		if (newNode->content.key < tmp->content.key){
			tmp->leftChild = newNode;
		}
		else if (newNode->content.key > tmp->content.key){
			tmp->rightChild = newNode;
		}
		else{ ; }
	}
}
/******************递归查找Search************************/
template <typename Type>
BstNode<Type>* Bst<Type>::Search(const Element<Type>&  _data)
{
	return Search(root,_data);
}
template <typename Type>
BstNode<Type>* Bst<Type>::Search(BstNode<Type>* node, const Element<Type>&  _data)
{
	if (node == nullptr)
		return nullptr;

	if (_data.key < node->content.key)
		return Search(node->leftChild,_data);
	else if (_data.key > node->content.key)
		return Search(node->rightChild, _data);
	else 
		return node;
}
/******************迭代查找IterSearch************************/
template <typename Type>
BstNode<Type>* Bst<Type>::IterSearch(const Element<Type>&  _data)
{
	BstNode<Type> *cur = root;
	while (cur){
		if (cur->content.key == _data.key)
			return cur;
		else if (_data.key < cur->content.key)
			cur = cur->leftChild;
		else if (_data.key > cur->content.key)
			cur = cur->rightChild; 
		else{ ; }
	}
	return nullptr;
}
/******************查找最大值节点************************/
template <typename Type>
BstNode<Type>* Bst<Type>::FindMax()
{
	return FindMax(root);
}
template <typename Type>
BstNode<Type>* Bst<Type>::FindMax(BstNode<Type>* node)
{
	BstNode<Type> *cur = node;

	if (!cur) return nullptr;//node为空,直接返回

	//cur = cur->leftChild;//cur指向node的左子树的父节点

	while (cur->rightChild)
		cur = cur->rightChild;

	return cur;
}
/******************查找最小值节点************************/
template <typename Type>
BstNode<Type>* Bst<Type>::FindMin()
{
	return FindMin(root);
}
template <typename Type>
BstNode<Type>* Bst<Type>::FindMin(BstNode<Type>* node)
{
	BstNode<Type> *cur = node;

	if (!cur) return nullptr;//node为空,直接返回

	//cur = cur->rightChild;//cur指向node的右子树的父节点

	while (cur->leftChild)
		cur = cur->leftChild;

	return cur;
}

/******************删除节点************************/
template <typename Type>
void Bst<Type>::Delete(const Element<Type>&  _data)
{
	BstNode<Type> *deleteNode = nullptr;
	BstNode<Type> *deleteNodeParent = nullptr;

	BstNode<Type> *minNode = nullptr;
	BstNode<Type> *maxNode = nullptr;

	deleteNode = Search(_data);
	if (!deleteNode) return;//deleteNode为空,表明BST中没有元素为_data的节点,直接返回
	
	if (deleteNode->leftChild){//deleteNode有左子树,得到deleteNode左子树的最大值节点
		maxNode = FindMax(deleteNode->leftChild);
	}
	if (deleteNode->rightChild){//deleteNode有右子树,得到deleteNode右子树的最小值节点
		minNode = FindMin(deleteNode->rightChild);
	}

	deleteNodeParent = FindParent(deleteNode);//找到deleteNode节点的父节点
	//maxNode和minNode的节点为空,表明deleteNode是一个叶子节点
	if (!maxNode && !minNode){
		if (deleteNodeParent->leftChild == deleteNode)
			deleteNodeParent->leftChild = nullptr;
		else
			deleteNodeParent->rightChild = nullptr;
		
		delete deleteNode;
	}
	//表明deleteNode最少有一个子树不空
	else{

		//1.将tmp节点的父节点和tmp的子节点连接
		BstNode<Type> *tmp = (maxNode == nullptr) ? minNode : maxNode;
		BstNode<Type> * tmpParent = FindParent(tmp);
		if (tmp->leftChild){//左孩子不空,右孩子必空.此情况对应的是 maxNode
			if (tmpParent->leftChild == tmp)//tmp是左孩子
				tmpParent->leftChild = tmp->leftChild;
			else
				tmpParent->rightChild = tmp->leftChild;
		}
		else{//右孩不空,左孩子必空,此情况对应的是 minNode
			if (tmpParent->leftChild == tmp)
				tmpParent->leftChild = tmp->rightChild;
			else
				tmpParent->rightChild = tmp->rightChild;
		}

		//2.将tmp节点和deleteNode的父节点连接
		if (deleteNodeParent == nullptr)
			root = tmp;
		else{

			if (tmp->content.key < deleteNodeParent->content.key)
				deleteNodeParent->leftChild = tmp;
			else
				deleteNodeParent->rightChild = tmp;
		}
		//3.将tmp节点的左右孩子连接上deleteNode的左右孩子
		tmp->leftChild = deleteNode->leftChild;
		tmp->rightChild = deleteNode->rightChild;

		delete deleteNode;
	}
}

/******************中序遍历InOrder************************/
template <typename Type>
void Bst<Type>::InOrder()
{
	InOrder(root);
}
template <typename Type>
void Bst<Type>::InOrder(BstNode<Type>* node)
{
	if (node == nullptr)
		return;

	InOrder(node->leftChild);
	std::cout << node->content.key << std::endl;
	InOrder(node->rightChild);
}
/******************层序遍历InOrder************************/
template <typename Type>
void Bst<Type>::LevelOrder()
{
	LevelOrder(root);
}
template <typename Type>
void Bst<Type>::LevelOrder(BstNode<Type>* node)
{
	queue<BstNode<Type>*> q;
	q.push(node);

	while (!q.empty()){
		int size = q.size();

		std::cout << "[";
		for (int i = 0; i < size; i++){
			BstNode<Type>* tmp = q.front();
			q.pop();

			std::cout << tmp->content.key << " ";
			
			if (tmp->leftChild) q.push(tmp->leftChild);
			if (tmp->rightChild) q.push(tmp->rightChild);
		}
		std::cout <<"]" <<std::endl;
	}
}
/******************查找结点的父节点FindParent************************/
template <typename Type>
BstNode<Type>* Bst<Type>::FindParent(BstNode<Type>* node)
{
	//node = root.表明node无父节点
	if (root == node)
		return nullptr;

	BstNode<Type>* cur = root;

	while (cur && root){
		//返回父节点
		if (cur->leftChild == node || cur->rightChild == node)
			return cur;

		//cur节点不是node的父节点,根据key确定从cur的左子树找还是右子树找
		if (node->content.key < cur->content.key)
			cur = cur->leftChild;
		else
			cur = cur->rightChild;
	}
	return nullptr;
}

#endif

main.cpp如下:

#include 
#include "Bst.h"


using namespace std;

int main()
{
	Bst<int> tree;
	Element<int> e1(5);
	Element<int> e2(4);
	Element<int> e3(3);
	Element<int> e4(9);
	Element<int> e5(1);
	Element<int> e6(7);
	/*
				5
			4			9
		3			7
	1	
	*/
	
	tree.Insert(e1);
	tree.Insert(e2);
	tree.Insert(e3);
	tree.Insert(e4);
	tree.Insert(e5);
	tree.Insert(e6);

	cout << "原树的中序遍历和层序遍历:" << endl;
	tree.InOrder();
	tree.LevelOrder();

	cout << "删除节点e2的中序遍历和层序遍历:" << endl;
	tree.Delete(e2);
	tree.InOrder();
	tree.LevelOrder();

	cout << "删除节点e1的中序遍历和层序遍历:" << endl;
	tree.Delete(e1);
	tree.InOrder();
	tree.LevelOrder();


	system("pause");
	return 0;
}

打印结果:
数据结构——实现一个二叉查找树(BST)_第1张图片

你可能感兴趣的:(数据结构,c++,二叉树)