二叉排序树

前言:二叉排序树的学习笔记

什么是二叉排序树

代码实现

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAXSIZE 100
#define OK 1
#define ERROR 0
// @author zpchcbd
// @time 2020.4.04 13.24
// @实现二叉排序树
typedef int ElemType;
typedef int Status;
typedef struct _TreeNode{
	ElemType nodeData;
	struct _TreeNode* pLeftTreeNode;
	struct _TreeNode* pRightTreeNode;
}TreeNode, *PTreeNode;
typedef struct _SqTree{
	TreeNode* pRootTreeNode;
	int iTreeSize;
}SqTree, *PSqTree;

// init root tree node
Status initRootTreeNode(SqTree* pSqTree, ElemType elem)
{
	if (pSqTree->pRootTreeNode != NULL)
		return ERROR;
	pSqTree->pRootTreeNode = malloc(sizeof(TreeNode));
	memset(pSqTree->pRootTreeNode, 0, sizeof(TreeNode));
	pSqTree->pRootTreeNode->nodeData = elem; //根节点的数据初始化为ElemType elem大小
	if (pSqTree->pRootTreeNode != NULL)
		return OK;
	else
		return ERROR;
}

// 二叉排序树插入结点
// 左子树所有结点的关键字(nodeData)均小于根节点的关键字
// 右子树所有结点的关键字(nodeData)均大于根节点的关键字
TreeNode* insertTreeNode(TreeNode* pTreeNode, ElemType elem)
{
	TreeNode* pNewTreeNode = NULL;
	if (pTreeNode != NULL && pTreeNode->nodeData > elem)
	{
		pTreeNode->pLeftTreeNode = insertTreeNode(pTreeNode->pLeftTreeNode, elem);
		return pTreeNode;
	}
	if (pTreeNode != NULL && pTreeNode->nodeData < elem)
	{
		pTreeNode->pRightTreeNode = insertTreeNode(pTreeNode->pRightTreeNode, elem);
		return pTreeNode;
	}
	pNewTreeNode = malloc(sizeof(TreeNode));
	memset(pNewTreeNode, 0, sizeof(TreeNode));
	pNewTreeNode->nodeData = elem;
	return pNewTreeNode;
}

// 二叉排序树寻找结点
// 左子树所有结点的关键字(nodeData)均小于根节点的关键字
// 右子树所有结点的关键字(nodeData)均大于根节点的关键字
TreeNode* findTreeNode(TreeNode* pTreeNode, ElemType elem)
{
	if (pTreeNode->nodeData == elem)
		return pTreeNode;
	else if (pTreeNode == NULL)
		return NULL;// 如果到了这里的话,那么就是遍历了相关的路径都没有查找
	else if (pTreeNode != NULL && pTreeNode->nodeData < elem)
		return findTreeNode(pTreeNode->pRightTreeNode, elem);
	else if (pTreeNode != NULL && pTreeNode->nodeData > elem)
		return findTreeNode(pTreeNode->pLeftTreeNode, elem);
	return 0;
}


// 中序的后继结点是当前右子树最左下的结点
TreeNode* getAfterNodeFromMiddle(TreeNode* pTreeNode)
{
	if (pTreeNode->pLeftTreeNode != NULL)
		return getAfterNodeFromMiddle(pTreeNode->pLeftTreeNode);
	else
		return pTreeNode;
}

// 寻找中序后继结点
TreeNode* findMiddleAfterTreeNode(TreeNode* pTreeNode)
{
	return getAfterNodeFromMiddle(pTreeNode->pRightTreeNode);
}

// 中序的前驱结点是当前左子树最右下的结点
TreeNode* getPreNodeFromMiddle(TreeNode* pTreeNode)
{
	if (pTreeNode->pRightTreeNode != NULL)
		return getPreNodeFromMiddle(pTreeNode->pRightTreeNode);
	else
		return pTreeNode;
}

// 寻找中序前驱结点
TreeNode* findMiddlePreTreeNode(TreeNode* pTreeNode)
{
	return getPreNodeFromMiddle(pTreeNode->pLeftTreeNode);
}

// 二叉排序树删除结点
// 左子树所有结点的关键字(nodeData)均小于根节点的关键字
// 右子树所有结点的关键字(nodeData)均大于根节点的关键字
// 删除结点的时候有多种情况
// - 1、当删除叶子结点的时候
// - - 那么直接删除该结点即可(完成)
// - 2、当删除不是叶子结点的时候,但是其结点有左子树或者右子树的情况
// - - 被删的时候只有左结点或者右节点的时候,那么用其结点的子树代替即可
// - 3、被删的时候只有左右结点的时候(有如下两种方法进行处理)
// - - - 用该结点的前驱结点代替(左子树最右下的结点),再删除后继结点
// - - - 或者用后继结点代替(右子树最左下的结点),删除前驱结点
 Status deleteTreeNode(TreeNode* pTreeNode, TreeNode* pPreTreeNode, ElemType elem)
{
	 pPreTreeNode = pTreeNode;
	 if (pTreeNode->nodeData == elem)
	 {
		 if (pTreeNode->pLeftTreeNode == NULL && pTreeNode->pRightTreeNode == NULL)
		 {
			// 你还需要判断下当前删除的结点是左叶子结点还是右叶子结点
			memset(pTreeNode, 0, sizeof(TreeNode)); // 第一种情况就是要删除的结点为叶子结点
			if (pPreTreeNode->pLeftTreeNode == pTreeNode)
				pPreTreeNode->pLeftTreeNode = NULL;
			else if(pPreTreeNode->pRightTreeNode == pTreeNode)
				pPreTreeNode->pRightTreeNode = NULL;
		}
		else if (pTreeNode->pLeftTreeNode!= NULL && pTreeNode->pRightTreeNode == NULL)
		{
			// 第二种情况,被删的结点,其结点只有左节点的时候,那么用其结点的左子树代替即可
			if (pPreTreeNode->pLeftTreeNode == pTreeNode)
				pPreTreeNode->pLeftTreeNode = pTreeNode->pLeftTreeNode;
			else if (pPreTreeNode->pRightTreeNode == pTreeNode)
				pPreTreeNode->pRightTreeNode = pTreeNode->pLeftTreeNode;
		}
		else if (pTreeNode->pLeftTreeNode == NULL && pTreeNode->pRightTreeNode != NULL)
		{
			// 第二种情况,被删的时候,其结点只有右结点的时候,那么用其结点的右子树代替即可
			if (pPreTreeNode->pLeftTreeNode == pTreeNode)
				pPreTreeNode->pLeftTreeNode = pTreeNode->pRightTreeNode;
			else if (pPreTreeNode->pRightTreeNode == pTreeNode)
				pPreTreeNode->pRightTreeNode = pTreeNode->pRightTreeNode;
		}
		else if (pTreeNode->pLeftTreeNode != NULL && pTreeNode->pRightTreeNode != NULL)
		{
			TreeNode* pTempTreeNode = NULL;
			// 第三种情况,被删的时候,其结点有左右结点的时候
			// 用该结点的前驱结点代替(左子树最右下的结点)
			pTempTreeNode = getPreNodeFromMiddle(pTreeNode);
			if (pPreTreeNode->pLeftTreeNode == pTreeNode)
				pPreTreeNode->pLeftTreeNode = pTempTreeNode;
			else if (pPreTreeNode->pRightTreeNode == pTreeNode)
				pPreTreeNode->pRightTreeNode = pTempTreeNode;
			// 再删除后继结点
			pTempTreeNode = getAfterNodeFromMiddle(pTreeNode);
			deleteTreeNode(pTempTreeNode, pTempTreeNode, pTempTreeNode->nodeData); // 第二个参数的pTempTreeNode只是为了满足参数提供
		}
		return OK;
	}
	else if (pTreeNode == NULL)
		return ERROR;// 如果到了这里的话,那么就是遍历了相关的路径都没有查找
	else if (pTreeNode != NULL && pTreeNode->nodeData < elem)
		return deleteTreeNode(pTreeNode->pRightTreeNode, pPreTreeNode, elem);
	else if (pTreeNode != NULL && pTreeNode->nodeData > elem)
		return deleteTreeNode(pTreeNode->pLeftTreeNode, pPreTreeNode, elem);
	return ERROR;
}

int main()
{
	// 初始化树的根节点
	SqTree sqTree;
	ElemType data[7];
	TreeNode* pFindTreeNode = NULL;
	TreeNode* pDeleteTreeNode = NULL;
	int i;
	memset(&sqTree, 0, sizeof(SqTree));
	initRootTreeNode(&sqTree, 50);
	// 二叉排序树插入相关的结点
	// 66 60 26 21 30 70 68
	for (i = 0; i < 7;i++)
		scanf("%d", &data[i]);
	for (i = 0; i < 7; i++)
		insertTreeNode(sqTree.pRootTreeNode, data[i]);
	// 二叉排序树的查找
	pFindTreeNode = findTreeNode(sqTree.pRootTreeNode, 68);
	printf("current find TreeNode's data -> %d\n", pFindTreeNode->nodeData);
	// 二叉排序树的删除
	deleteTreeNode(sqTree.pRootTreeNode, sqTree.pRootTreeNode, 68);
	return 0;
}
posted @ 2022-04-04 14:56  zpchcbd  阅读(43)  评论(0)    收藏  举报