二叉查找树
来源:互联网 发布:亿世界外包系统源码 编辑:程序博客网 时间:2024/06/05 09:19
bsTree.h
#ifndef BSTREE_H_INCLUDED#define BSTREE_H_INCLUDED#undef NULL#ifdef __cplusplus #define NULL 0#else #define NULL ((void *)0)#endif/*二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它是一棵空树或者具有以下性质: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。后继: 如果二叉查找树的关键字互不相同,则一个节点x的后继是大于x.key的最小关键字节点。简单来说:前驱就是节点x左子树key最大的节点,后继是节点x右子树中key最小的节点。*/typedef struct tag_bsTree{ struct tag_bsTree *pLNode; //左孩子 struct tag_bsTree *pRNode; //右孩子 struct tag_bsTree *pPNode; //双亲、 int key;}bsTree;//为树分配一个新节点bsTree* getBsNode(int key);/*将一个节点插入bsTree。按照插入节点的大小以及二叉树的性质插入*/bsTree* bsInsert(bsTree *pNewTreeNode, bsTree* pstBsRoot);//查找bsTree* bsSearch(int key , bsTree* pstBsRoot);/*在二叉查找树种删除一个元素,返回bool。分三种情况进行处理: 1.p为叶子节点,直接删除该节点,再修改其父节点的指针 2.p为单支节点(即只有左子树或右子树)。让p的子树与p的父亲节点相连,删除p即可 3.p的左子树和右子树均不空。找到p的后继y,因为y一定没有左子树,所以可以删除y,并让y的父亲节点成为y的右子树的父亲节点,并用y的值代替p的值;或者方法二是找到p的前驱x,x一定没有右子树,所以可以删除x,并让x的父亲节点成为y的左子树的父亲节点。如图c。*/bsTree* bsDel(bsTree *pstDelNode, bsTree *pstBsRoot);//获取pstBsRoot之后的最大key所在位置bsTree *bsGetMaxNode(bsTree *pstBsRoot);//获取pstBsRoot之后的最小key所在位置bsTree *bsGetMinNode(bsTree *pstBsRoot);//获取pNode的后继bsTree* bsGetNext(bsTree *pNode);//获取pNode的前驱bsTree* bsGetPre(bsTree *pNode);#endif // BSTREE_H_INCLUDED
#include "bsTree.h"#include "memory.h"#define RETURN_ERR -1#define RETURN_OK 0bsTree* getBsNode(int key){ bsTree *pNewNode = NULL; pNewNode = (bsTree*)malloc(sizeof(bsTree)); if (NULL == pNewNode) { return NULL; } memset(pNewNode, 0, sizeof(bsTree)); pNewNode->key = key; return pNewNode;}/*函数功能:插入一个节点到二叉查找树函数入参:bsTree *pNewTreeNode 待插入节点 bsTree* pstBsRoot 二叉树的根节点函数出参:无函数返回值:二叉树根节点(有可能改变二叉树根节点的位置)其他: 该函数也可以使用递归实现*/bsTree* bsInsert(bsTree *pNewTreeNode, bsTree* pstBsRoot){ bsTree *pstTmp = NULL; bsTree *pstPar = NULL; //父节点的位置 //如果新节点是空,则入参错误 if (NULL == pNewTreeNode) { return NULL; //返回NULL,要求调用者需要先判断返回值,返回值不空才能修改根节点的位置 } pstTmp = pstBsRoot; while (NULL != pstTmp) { pstPar = pstTmp; //先保存父节点 if (pNewTreeNode->key <= pstTmp->key) //严格来说如果等于条件成立,说明节点存在不允许再次插入,需要清理pNewTreeNode的内存 { pstTmp = pstTmp->pLNode; } else { pstTmp = pstTmp->pRNode; } } pNewTreeNode->pPNode = pstPar; if (NULL == pstPar) { pstBsRoot = pNewTreeNode; } else if (pNewTreeNode->key <= pstPar->key) { pstPar->pLNode = pNewTreeNode; } else { pstPar->pRNode = pNewTreeNode; } return pstBsRoot;}/*函数功能:根据key确定节点在二叉查找树的位置函数入参:int key 待查找节点的key值 bsTree* pstBsRoot 树的根节点函数出参:无函数返回值:key对应的节点在二叉查找树中的位置,找不到返回NULL其他: 该函数也可以使用递归实现*/bsTree* bsSearch(int key , bsTree* pstBsRoot){ bsTree *pTmp = pstBsRoot; while (NULL != pTmp) { if (key < pTmp->key) { pTmp = pTmp->pLNode; } else if (key > pTmp->key) { pTmp = pTmp->pRNode; } else { break; } } return pTmp;}/*函数功能:删除一个节点函数入参:bsTree *pstDelNode 待删除节点的位置 bsTree* pstBsRoot 二叉树的根节点函数出参:无函数返回值:删除后的根节点其他:*/bsTree* bsDel(bsTree *pstDelNode, bsTree *pstBsRoot){ bsTree *pTmp1 = NULL; bsTree *pTmp2 = NULL; //待删除节点的左孩子或者右孩子为空 if ((NULL == pstDelNode->pLNode) || (NULL == pstDelNode->pRNode)) { pTmp2 = pstDelNode; } else { pTmp2 = bsGetNext(pstDelNode); //pstDelNode的左右孩子都不为空的时候,需要找到该节点的后继 } if (NULL != pTmp2->pLNode) { pTmp1 = pTmp2->pLNode; //后继节点的左孩子不为空,则保持后继的左孩子 } else { pTmp1 = pTmp2->pRNode; //此时pTmp1,有可能为空 } if (NULL != pTmp1) { pTmp1->pPNode = pTmp2->pPNode; } if (NULL == pTmp2->pPNode) { pstBsRoot = pTmp1; } else if (pTmp2 == pTmp2->pPNode->pLNode) { pTmp2->pPNode->pLNode = pTmp1; } else { pTmp2->pPNode->pRNode = pTmp1; } if (pTmp2 != pstDelNode) { pstDelNode->key = pTmp2->key; } if (NULL != pTmp2) { free(pTmp2); } return pstBsRoot; //删除节点的时候根节点肯定存在(或为NULL)}//获取pstBsRoot之后的最大key所在位置bsTree *bsGetMaxNode(bsTree *pstBsRoot){ bsTree *pTmp = pstBsRoot; if (NULL == pstBsRoot) { return NULL; //子树不存在 } while (NULL != pTmp->pRNode) //为空的时候就查找到了哦 { pTmp = pTmp->pRNode; } return pTmp;}//获取pstBsRoot之后的最小key所在位置bsTree *bsGetMinNode(bsTree *pstBsRoot){ bsTree *pTmp = pstBsRoot; if (NULL == pstBsRoot) { return NULL; //子树不存在 } while (NULL != pTmp->pLNode) { pTmp = pTmp->pLNode; } return pTmp;}bsTree* bsGetNext(bsTree *pNode){ bsTree *pPer = NULL; //父节点 bsTree *pTmp = NULL; if (NULL != pNode->pRNode) { return bsGetMinNode(pNode->pRNode); //右孩子存在,直接查找子树的最小key } /* 如果pNode没有右孩子。则pNode有以下两种可能: (01) pNode是"一个左孩子",则"pNode的后继结点"为 "它的父结点"。 (02) pNode是"一个右孩子",则查找"pNode的最低的父结点,并且该父结点要具有左孩子" */ pTmp = pNode; pPer = pNode->pPNode; while ((NULL != pPer) && (pTmp == pPer->pRNode)) //父节点不为空且pNode是有孩子,查找pNode的父节点的具有左孩子的先祖 { pTmp = pPer; pPer = pPer->pPNode; } return pPer;}bsTree* bsGetPre(bsTree *pNode){ bsTree *pPer = NULL; //父节点 bsTree *pTmp = NULL; if (NULL != pNode->pLNode) { return bsGetMaxNode(pNode->pRNode); //左孩子存在,直接查找子树的最大key } /* 如果pNode没有左孩子。则pNode有以下两种可能: (01) pNode是"一个右孩子",则"pNode的后继结点"为 "它的父结点"。 (02) pNode是"一个左孩子",则查找"pNode的父结点,并且该父结点要具有右孩子的父节点(不好用语言表述)" */ pTmp = pNode; pPer = pNode->pPNode; while ((NULL != pPer) && (pTmp == pPer->pLNode)) { pTmp = pPer; pPer = pPer->pPNode; } return pPer;}main.c
#include <stdio.h>#include "bsTree.h"bsTree *g_pstBsRoot = NULL;//将i,转换成key,用于构造比较平衡的二叉树int getKey(int i){ switch (i) { case 0: return 3; case 1: return 2; case 2: return 4; case 3: return 8; case 4: return 7; case 5: return 11; case 6: return 9; case 7: return 12; case 8: return 10; case 9: return 11; default : return 1; }}void printBsTree(bsTree *pTreeRoot){ if (NULL == pTreeRoot) { return; } printBsTree(pTreeRoot->pLNode); //访问根节点 printf("%d\t", pTreeRoot->key); printBsTree(pTreeRoot->pRNode); return;}int main(){ bsTree *pTmp = NULL; bsTree *pNew = NULL; int i; int j; pNew = getBsNode(5); if (NULL == pNew) { exit(0); } pTmp = bsInsert(pNew, g_pstBsRoot); if (0 == pTmp) { exit(0); } g_pstBsRoot = pTmp; //判断之后再赋值,防止插入失败导致根节点指向空,从而造成内存泄漏 for (i = 0; i < 11; i++) { j = getKey(i); pNew = getBsNode(j); if (NULL == pNew) { exit(0); } pTmp = bsInsert(pNew, g_pstBsRoot); if (NULL == pTmp) { exit(0); } g_pstBsRoot = pTmp; } printBsTree(g_pstBsRoot); //执行中序遍历之后,key按照从小到大的顺序排列 pTmp = bsSearch(0, g_pstBsRoot); printf("\npTmp = %p", pTmp); //打印key对应节点的位置 pTmp = bsSearch(4, g_pstBsRoot); pTmp = bsGetPre(pTmp); //获取4的前驱 printf("\n%d", pTmp->key); pTmp = bsSearch(4, g_pstBsRoot); pTmp = bsGetNext(pTmp); //获取4的后继 printf("\n%d", pTmp->key); pTmp = bsSearch(1, g_pstBsRoot); pTmp = bsGetPre(pTmp); //获取1的前驱,应该返回NULL printf("\npTmp = %p\n", pTmp); pTmp = bsSearch(5, g_pstBsRoot); g_pstBsRoot = bsDel(pTmp, g_pstBsRoot); printBsTree(g_pstBsRoot); //执行中序遍历之后,key按照从小到大的顺序排列 return 0;}
阅读全文
0 0
- 查找--二叉查找树
- 二叉树、二叉查找树
- 二叉树 & 二叉查找树
- 【查找结构】二叉查找树
- 查找之二叉树查找
- 查找之二叉树查找
- 查找:二叉查找树总结
- 二叉树查找树...
- 二叉树查找树
- 查找--遍历二叉树
- 二叉查找树
- 二叉查找树实现
- 二叉查找树
- 动态二叉查找树
- 最优二叉查找树
- 二叉查找树
- 二叉查找树
- 平衡二叉查找树
- TensorFlow之CNN图像分类及模型保存与调用
- SpringBoot非官方教程 | 第二篇:Spring Boot配置文件详解
- 除去文档中英文 数字 ?
- SpringBoot非官方教程 | 第三篇:SpringBoot用JdbcTemplates访问Mysql
- method initializationerror not found:JUnit4单元测试报错问题
- 二叉查找树
- java:Java入门第三季第四课:异常处理机制
- SpringBoot非官方教程 | 第四篇:SpringBoot 整合JPA
- “高级”CSS样式一般应用于控制网页内容的外观。附加样式表分为内嵌样式表和外部样式表两种方式。
- SpringBoot非官方教程 | 第六篇:springboot整合mybatis
- Mishka and Interesting sum CodeForces
- Python raw_input含中文时CMD下乱码
- SpringBoot非官方教程 | 第七篇:springboot开启声明式事务
- PHP的自动加载