C++用类实现二叉排序树(也称二叉查找树,二叉搜索树)

一、简介:

二叉排序树(也称为二叉搜索树或BST)是一种特殊的二叉树,具有以下性质:

  1. 左子树上的所有节点的值都小于根节点的值。
  2. 右子树上的所有节点的值都大于根节点的值。
  3. 左子树和右子树也都是二叉排序树。

根据这些性质,二叉排序树的遍历结果如下:

  1. 前序遍历(Preorder Traversal):根节点 -> 左子树 -> 右子树。这意味着你首先访问根节点,然后按照前序遍历的顺序依次访问左子树和右子树。前序遍历可以用来复制整个二叉排序树。

  2. 中序遍历(Inorder Traversal):左子树 -> 根节点 -> 右子树。中序遍历对于二叉排序树来说,会按照升序访问树中的节点值,因此得到的结果是一个按照升序排列的节点值序列。这使得中序遍历在查找、排序等操作中非常有用。

  3. 后序遍历(Postorder Traversal):左子树 -> 右子树 -> 根节点。后序遍历的结果是从下到上,从叶子节点到根节点的顺序,常用于释放二叉树的内存空间。

这些遍历方式可以根据具体需求来选择。前序遍历通常用于复制树结构,中序遍历用于按顺序访问树中的节点,后序遍历用于释放资源。在二叉排序树中,中序遍历是最常用的,因为它可以按顺序访问节点值,从而实现搜索和排序等操作。

二、实现

关于用C++结构体实现的二叉树:二叉树的构建(C++)_二叉树的建立c++-CSDN博客

这里我们使用类来实现一个功能相对完整的二叉树,这个二叉树是根据值的大小构建的,从小到大分别是左节点,根节点,右节点的插入节点时,所以每次插入新节点时会从根节点开始,跟所有节点的值进行判断大小,最后插入到合适位置。
二叉树节点类:

#pragma once
#include<iostream>
using namespace std;

template<typename T>
class BinaryTree;

template<typename T>
class BinaryTreeNode
{
	friend class BinaryTree<T>;
private:
	T val;//数据域
	BinaryTreeNode<T>* pLeft;//左节点(子树)
	BinaryTreeNode<T>* pRight;//右节点(子树)
	BinaryTreeNode<T>* pParent;//父节点

public:
	BinaryTreeNode(T val, BinaryTreeNode<T>* pLeft = nullptr,BinaryTreeNode<T>* pRight=nullptr,BinaryTreeNode<T>* pParent = nullptr);
	~BinaryTreeNode();
public:
	
	//遍历以当前节点为根节点的子树
	void preOrder(); //前序遍历
	void inOrder();//中序
	void postOrder();//后序
	int getHeight();//求以当前节点为根节点的树的深度
	int getSize();//求以当前节点为根节点的树的节点数量
	void insert(const T& val);//插入节点
};
template<typename T>
BinaryTreeNode<T>::BinaryTreeNode(T val, BinaryTreeNode<T>* pLeft, BinaryTreeNode<T>* pRight, BinaryTreeNode<T>* pParent) 
:val(val),pLeft(pLeft),pRight(pRight),pParent(pParent){

}

template<typename T>
BinaryTreeNode<T>::~BinaryTreeNode() {
	pLeft = nullptr;
	pRight = nullptr;
	pParent = nullptr;
}

template<typename T>
//遍历以当前节点为根节点的子树
//前序遍历
void BinaryTreeNode<T>::preOrder() {
	cout << val << endl;
	if (pLeft != nullptr) {
		pLeft->preOrder();
	}
	if (pRight != nullptr) {
		pRight->preOrder();
	}
}
//中序遍历
template<typename T>
void BinaryTreeNode<T>::inOrder() {
	if (pLeft != nullptr) {
		pLeft->preOrder();
	}
	
	cout << val << endl;
	if (pRight != nullptr) {
		pRight->preOrder();
	}
	
}
//后序遍历
template<typename T>
void BinaryTreeNode<T>::postOrder() {
	if (pLeft != nullptr) {
		pLeft->preOrder();
	}
	
	if (pRight != nullptr) {
		pRight->preOrder();
	}
	cout << val << endl;
}
//求以当前节点为根节点的树的深度
template<typename T>
int BinaryTreeNode<T>::getHeight() {
	//如果pLeft为空返回0,不为空继续查找
	int leftDepth = pLeft?pLeft->getHeith():0;
	int rightDepth = pRight?pRight->getHeight():0;
	return 1 + (leftDepth > rightDepth ? leftDepth : rightDepth);
}

//求以当前节点为根节点的树的节点数量
template<typename T>
int BinaryTreeNode<T>::getSize() {
	int leftNum = pLeft ? pLeft->getSize():0;
	int rightNum = pRight ? pRight->getSize():0;
	return 1 + leftNum + rightNum;
}

//插入节点
template<typename T>
void BinaryTreeNode<T>::insert(const T& val) {
	if (val < this->val) {
		if (pLeft != nullptr) {
			pLeft->insert(val);
		}
		else {
			pLeft = new BinaryTreeNode<T>(val);
			return;
		}
	}
	else if (val > this->val) {
		if (pRight != nullptr) {
			pRight->insert(val);
		}
		else {
			pRight = new BinaryTreeNode<T>(val);
			return;
		}
	}
	else //与某个节点相等,不插入
		return;
}

二叉树类:

#pragma once
#include "BinaryTreeNode.h"
template<typename T>
class BinaryTree
{
public:
	BinaryTree();
	~BinaryTree();
private:
	//存放根节点
	BinaryTreeNode<T> *pRoot;
public:
	void insert(const T& val);//插入一个值
	void preOrder(); //前序遍历
	void inOrder();//中序
	void postOrder();//后序
	int getHeight();//求以当前节点为根节点的树的深度
	int getSize();//求以当前节点为根节点的树的节点数量
	void Delete(const T& val);//删除节点
};

template<typename T>
BinaryTree<T>::BinaryTree():pRoot(nullptr)
{
	
}
template<typename T>
BinaryTree<T>::~BinaryTree()
{
	delete pRoot;
	pRoot = nullptr;
}

//前序遍历
template<typename T>
void BinaryTree<T>::preOrder() {
	pRoot->preOrder();
}
//中序遍历
template<typename T>
void BinaryTree<T>::inOrder() {
	pRoot->inOrder();
} 

//后序遍历
template<typename T>
void BinaryTree<T>::postOrder() {
	pRoot->postOrder();
}

//求以当前节点为根节点的树的深度
template<typename T>
int BinaryTree<T>::getHeight() {
	  return pRoot->getHeight();
}

//求以当前节点为根节点的树的节点数量
template <typename T>
int BinaryTree<T>::getSize() {
	return pRoot->getSize();
}

//插入一个值
template<typename T>
void BinaryTree<T>::insert(const T& val) {
	if (pRoot == nullptr) {//如果根节点还为空时,直接新建一个根节点
		pRoot= new BinaryTreeNode<T>(val);
	}
	pRoot->insert(val);
}

//删除节点,删除后要调整二叉树,满足左小右大结构,这个有点麻烦,查了好多资料
template<typename T>
void BinaryTree<T>::Delete(const T& val) {
	BinaryTreeNode<T>* pNode = pRoot;
	//首先遍历查找要删除的节点
	while (pNode != nullptr&&pNode->val != val) {
		if (val > pNode->val)
			pNode = pNode->pRight;
		else if (val < pNode->val)
			pNode = pNode->pLeft;
	}
	//没有找到该节点
	if (pNode == nullptr) {
		cout << "未找到要删除的节点" << endl;
	}
	else {//要删除的节点存在,分三种情况
		//第一种情况:要删除的是叶子节点
		if (pNode->pLeft == nullptr&&pNode->pRight == nullptr) {
			delete pNode;
		}
		//第二种情况:要删除的节点有一个节点,可再细分为只有左节点或者右节点
		else if (pNode->pLeft != nullptr&&pNode->pRight == nullptr) {
			BinaryTreeNode<T>* pTMP = pNode;
			pNode = pNode->pLeft;
			delete pTMP;
		}
		else if (pNode->pLeft == nullptr&&pNode->pRight != nullptr) {
			BinaryTreeNode<T>* pTMP = pNode;
			pNode = pNode->pRight;
			delete pTMP;
		}
		//第三种情况:要删除的节点既有左节点,又有右节点
		else {
			//找到一个后继节点值比要删除的节点大,但是最接近要删除的节点,即为要删除的节点的右节点中的最小值
			BinaryTreeNode<T>* pTMP = pNode->pRight;
			while (pTMP->pLeft != nullptr)
				pTMP = pTMP->pLeft;
			//将找到的这个后继节点的值跟要删除的节点值交换
			//此时有两种情况,这个后继节点有右节点或者没有右节点
			//1.如果没有右节点,问题变成整个问题的第一种情况,因为后继节点是个叶子节点,交换后直接删除
			if (pTMP->pRight == nullptr) {
				pNode->val = pTMP->val;
				delete pTMP;
			}
			//2.如果有右节点,问题变成整个问题的第二种情况
			else {
				pNode->val = pTMP->val;
				BinaryTreeNode<T>* pNodeTMP = pTMP;
				pTMP = pTMP->pRight;
				delete pNodeTMP;
			}
	
		}
		
	}
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值