二叉排序树

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

什么是二叉排序树

代码实现

#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 @   zpchcbd  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
历史上的今天:
2020-04-04 Thinkphp 5.0.x 未开启强制路由导致的RCE 漏洞分析
点击右上角即可分享
微信分享提示