二叉排序树
前言:二叉排序树的学习笔记
什么是二叉排序树
代码实现
#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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源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 漏洞分析