查找——二叉排序树(代码超详细注释)

二叉排序树是查找中一种很重要的数据结构,能很方便地进行结点的增添和删除。其规则为,所有左子树的结点的值都要小于父亲结点,所有右子树的结点的值都要大于父亲结点的,这样,就能做到“基本有序”,查找起来也很方便!直接上代码:

//BST.h
#pragma once
/*--------------------------------------
*		  二叉排序树定义			
*---------------------------------------*/

typedef int ElemType;

//二叉排序树结点的定义 
typedef struct BinarySortTreeNode
{
	ElemType data;//数据域
	struct BinarySortTreeNode* leftChild;//指向左子树
	struct BinarySortTreeNode* rightChild;//指向右子树
	struct BinarySortTreeNode* parent;//指向其双亲
	int height;//记录结点深度
}BSTNode,*BST;
//Sign.h
#pragma once 
/*--------------------------------------
*		记录一些自定义的符号定义
*--------------------------------------*/

#define YES 1
#define NO 0
#define OK 1
#define FALSE 0
#define ERROR -1

typedef int status; //状态
//BSTOperate.h
#pragma once
/*------------------------------------------
*		关于二叉排序树的一些操作
*--------------------------------------------*/
#include "BST.h"
#include "Sign.h"

//函数功能:创建一棵树
//传入参数:初始的第一个数据
//返回值:返回一棵空树
BST Initialize(ElemType data);

//函数功能:销毁一颗树
//传入参数:传入这棵树的引用
//返回值:无
void Destroy(BST &tree);

//函数功能:更新树高
//传入参数:传入树
//返回值:无
void UpdateHeight(BST &tree, int height = 1);

//函数功能:搜索结点是否在树中
//传入参数:搜索的值、待搜索树以及一个结点指针用来获得找到的结点的位置或者待插入结点的父结点位置
//返回值:状态值YES or NO
status Search(ElemType data, BST tree, BSTNode* &p);

//函数功能:插入结点
//传入参数:要插入的数据和树
//返回值:状态值OK or FALSE
status Insert(ElemType data, BST tree);

//函数功能:删除结点
//传入参数:要删除的数值以及树
//返回值:状态值OK or FALSE
status Delete(ElemType data, BST &tree);
//BSTSort.h
#pragma once
/*---------------------------------------------
*			二叉排序树排序函数
*---------------------------------------------*/

#include "BST.h"

//函数功能:二叉排序树排序输出
//传入参数:二叉排序树
//返回值:无
void BSTSort(BST tree);
//BSTOperate.cpp
/*------------------------------------------
*		关于二叉排序树的一些操作
*--------------------------------------------*/

#include "BSTOperate.h"

//函数功能:创建一棵树
//传入参数:初始的第一个数据
//返回值:返回一棵空树
BST Initialize(ElemType data)
{
	BST tree;
	tree = new BSTNode;//创建一颗新树
	tree->data = data;//数据域赋值
	tree->height = 1;//新树根结点的高度为1
	tree->parent = nullptr;//新树根结点的双亲为空
	tree->leftChild = tree->rightChild = nullptr;//新树根结点的左右孩子初始为空

	return tree;
}

//函数功能:销毁一颗树
//传入参数:传入这棵树的引用
//返回值:无
void Destroy(BST& tree)
{
	//采用左右孩子递归的方法进行销毁树
	if (tree != nullptr)
	{
		Destroy(tree->leftChild);
		Destroy(tree->rightChild);
		delete tree;//销毁前一个结点
		tree = nullptr;//重置为空指针
	}
}


//函数功能:搜索结点是否在树中
//传入参数:搜索的值、待搜索树以及一个结点指针用来获得找到的结点的位置或者待插入结点的父结点位置
//返回值:状态值YES or NO
status Search(ElemType data, BST tree,BSTNode* &p)
{
	if (tree != nullptr)
	{
		p = tree;
	}
	//当树为空时说明结点未在树内
	if (tree == nullptr)
	{
		return NO;
	}
	//当找到搜索的值时,返回找到的结点的指针
	else if (data == tree->data)
	{
		return YES;
	}
	//当查找的结点的数据比树要大时,去树的右子树找
	else if (data > tree->data)
	{
		Search(data, tree->rightChild,p);
	}
	//当查找的结点的数据比树要小时,去树的左子树找
	else if (data < tree->data)
	{
		Search(data, tree->leftChild,p);
	}
}

//函数功能:更新树高
//传入参数:传入树
//返回值:无
void UpdateHeight(BST &tree,int height)
{
	//从树的根节点开始向下递归计算出各个子树的高
	if (tree != nullptr)
	{
		tree->height = height;
		UpdateHeight(tree->leftChild, height + 1);
		UpdateHeight(tree->rightChild, height + 1);
	}
}

//函数功能:插入结点
//传入参数:要插入的数据和树
//返回值:状态值OK or FALSE
status Insert(ElemType data, BST tree)
{
	BSTNode *location;//用来获得插入结点的父结点的位置
	//当要插入的数值存在时
	if (Search(data,tree,location) == YES)
	{
		return FALSE;
	}
	//当要插入的数值不存在时,先将这个数值变成一个结点
	BSTNode *node = new BSTNode;
	node->data = data;
	node->parent = nullptr;
	node->leftChild = node->rightChild = nullptr;

	//location为待插入结点的父结点,注意,该父结点一定为叶子结点
	//然后判断结点应插在左孩子还是右孩子
	if (location->data > node->data )
	{
		location->leftChild = node;
		node->parent = location;
	}
	else
	{
		location->rightChild = node;
		node->parent = location;
	}

	//最后更新一下树高
	UpdateHeight(tree);
	return OK;
}

//函数功能:删除结点
//传入参数:要删除的数值以及树
//返回值:状态值OK or FALSE
status Delete(ElemType data, BST &tree)
{
	BSTNode *location;//用来确定要删除的结点的位置
	//当要删除的结点不存在时
	if (Search(data,tree,location) == NO)
	{
		return FALSE;
	}

	//当待删除结点的左子树为空时
	if (location->leftChild == nullptr)
	{
		(location->parent->leftChild == location ? location->parent->leftChild : location->parent->rightChild) = location->rightChild;//用来判断删除结点自身是其父亲的左子树还是右子树
		if (location->rightChild!=nullptr) location->rightChild->parent = location->parent;//更新删除结点的左子树的父亲
		delete location;//删除结点
		location = nullptr;//置空
	}
	//当待删除结点的右子树为空时
	else if (location->rightChild == nullptr)
	{
		(location->parent->leftChild == location ? location->parent->leftChild : location->parent->rightChild) = location->leftChild;//用来判断删除结点自身是其父亲的左子树还是右子树
		location->leftChild->parent = location->parent; // 更新删除结点的右子树的父亲
		delete location;//删除结点
		location = nullptr;//置空
	}
	//当左、右子树都不为空时,找直接后继结点替代被删除的结点
	else
	{
		BSTNode *next = location->rightChild;//next为location结点的直接后继结点
		
		//找直接后继结点
		while (next->leftChild != nullptr)
		{
			next = next->leftChild;
		}
		location->data = next->data;//将删除结点的数据用直接后继结点的数据替换
		//下面两行代码将直接后继结点的右孩子替换直接后继结点
		next->parent->leftChild = next->rightChild;
		if (next->rightChild != nullptr) next->rightChild->parent = next->parent;

		delete next;//将直接后继结点删除
		next = nullptr;//置空
	}
	//最后更新树高
	UpdateHeight(tree);
	return OK;
}
//BSTSort.cpp
/*---------------------------------------------
*			二叉排序树排序函数
*---------------------------------------------*/

#include "BSTSort.h"
#include <iostream>

//函数功能:二叉排序树排序输出
//传入参数:二叉排序树
//返回值:无
void BSTSort(BST tree)
{
	//采用中序遍历法进行排序
	if (tree != nullptr)
	{
		BSTSort(tree->leftChild);
		std::cout << tree->data << "\t";
		BSTSort(tree->rightChild);
	}
}
//main.cpp
/*---------------------------------------------------
*          二叉搜索树代码实现(主函数)
*---------------------------------------------------*/

#include <iostream>
#include "BST.h"
#include "BSTOperate.h"
#include "BSTSort.h"

using namespace std;

int main()
{
	BST tree;

    //测试
	tree = Initialize(62);

	Insert(58, tree);
	Insert(88, tree);
	Insert(47, tree);
	Insert(73, tree);
	Insert(99, tree);
	Insert(35, tree);
	Insert(51, tree);
	Insert(93, tree);

	Delete(88, tree);
	Delete(99, tree);
	Delete(0, tree);

	BSTSort(tree);

	Destroy(tree);

	cout << endl;
	system("pause");
	return 0;
}

乍一看,实现代码很复杂,很长,但仔细阅读你就会发现,所有代码采用的是多文件形式,函数声明和函数定义分离,避免单个文件过于臃肿,而且,代码中注释很多,很详细。

运行效果:

《查找——二叉排序树(代码超详细注释)》

PS:对于二叉排序树来说,并不需要记录树高和更新树高,在这里显得多余,但我们这么做是为了给接下的改进版——平衡二叉树做准备。

 

                       二叉排序树的原理请参看《大话数据结构》P313–P328

    原文作者:二叉查找树
    原文地址: https://blog.csdn.net/sj2050/article/details/81356321
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞