IDE:codebloks,编译器:gcc5.1.0
二叉搜索树和我们通常的二叉树还是有一定的区别,顾名思义,一颗二叉搜索树以一颗二叉树来组织,其中每一个结点就是一个对象。除了key(关键字)和卫星数据外,每个节点还包括left(左孩子指针)、right(右孩子指针)和p。如果孩子结点不存在则为NULL。
二叉搜索树的性质如下:
设x是二叉搜索树中的一个结点。如果y是x的左子树中的一个结点,那么y.key≤x.key。如果y是x右子树中的一个结点,那么y.key≥x.key。图a和b正好说明了这一点。

二叉搜索树的遍历有三种,分别为先序遍历(perorder tree walk)、中序遍历(inorder tree walk)、后续遍历(postorder tree walk)。
1.首选定义二叉搜索树结点的数据结构,为了简单期间,只定义了关键字,左孩子和右孩子指针本例子中的二叉搜索树如图c所示:

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <stdbool.h>
//binary search tree
struct BSTNode
{int data;struct BSTNode *pLchild;struct BSTNode *pRchild;struct BSTNode *pParent;
};

2.下面分别是三种遍历的C语言实现。唯一不同的地方是输出关键字的位置不void PreTraverseBSTree(pBstNode pBST)

void PreTraverseBSTree(struct BSTNode *pBST)
{if(NULL != pBST){printf("数据为:%d,父节点地址为:%p\n",pBST ->data,pBST ->pParent);if(NULL != pBST ->pLchild )PreTraverseBSTree(pBST ->pLchild);if(NULL != pBST ->pRchild)PreTraverseBSTree(pBST ->pRchild);}
}void InTraverseBSTree(struct BSTNode *pBST)
{if(NULL != pBST){if(NULL != pBST ->pLchild )PreTraverseBSTree(pBST ->pLchild);printf("数据为:%d,父节点地址为:%p\n",pBST ->data,pBST ->pParent);if(NULL != pBST ->pRchild)PreTraverseBSTree(pBST ->pRchild);}
}void PostTraverseBSTree(struct BSTNode *pBST)
{if(NULL != pBST){if(NULL != pBST ->pLchild )PreTraverseBSTree(pBST ->pLchild);if(NULL != pBST ->pRchild)PreTraverseBSTree(pBST ->pRchild);printf("数据为:%d,父节点地址为:%p\n",pBST ->data,pBST ->pParent);}
}

3.下面是查找的C语言实现。第一个版本是自己实现的,在写的过程中,想到了是不是可以去掉return,去掉return编译器报警,经过一番查找资料和思考,发现有没有return不会影响结果,报警的原因是SearchBSTree()的返回值类型是pBstNode,如果去掉return就没有返回值,类型不匹配就会报警。版本1没有版本2效率高,版本2没有版本3效率高,版本2和版本3参考自《算法导论》。版本3采用了while循环展开递归,用一种迭代方式重写这个过程。对于大多数计算机,迭代版本的效率要高很多。

//查找成功返回该结点的地址,失败返回NULL
struct BSTNode *SearchBSTree(struct BSTNode *pBST,int key)  //版本1
{if(NULL == pBST)return NULL;else if(key < pBST ->data)return SearchBSTree(pBST ->pLchild,key);else if(key > pBST ->data)return SearchBSTree(pBST ->pRchild,key);else return pBST;
}struct BSTNode *SearchBSTree(struct BSTNode *pBST,int key)  //版本2
{if(NULL == pBST || key == pBST ->data)return pBST;else if(key < pBST ->data)return SearchBSTree(pBST ->pLchild,key);else return SearchBSTree(pBST ->pRchild,key);
}struct BSTNode *SearchBSTree(struct BSTNode *pBST,int key)  //版本3
{while(NULL != pBST && key != pBST ->data){if(key < pBST ->data)pBST = pBST ->pLchild;else pBST = pBST ->pRchild;}return pBST;
}

4.在二叉搜索树中寻找最大值和最小值。由二叉搜索树的性质可知,我们总能在二叉搜索树中找到一个元素,两个拥有相同父结点的子结点中,左结子点的值肯定小于父节点,也小于右子结点,所以最小值总在二叉搜索树的左子树中,最大值总在右子树中。实现的代码如下:时间复杂度为O(h)。

struct BSTNode *SearchMinBSTree(struct BSTNode *pBST,int *pMinData)//查找二叉搜索树中最小的值
{while(NULL != pBST ->pLchild){pBST = pBST ->pLchild;}*pMinData = pBST ->data;return pBST;
}
struct BSTNode *SearchMaxBSTree(struct BSTNode *pBST,int *pMaxData) //查找二叉搜索树中最大的值
{while(NULL != pBST ->pRchild){pBST = pBST ->pRchild;}*pMaxData = pBST ->data;return pBST;
}

5.向二叉树中插入一个元素

void InsertBSTree(struct BSTNode *pBST,int InsertVal) //插入元素
{struct BSTNode *pRoot = pBST;//记录根节点地址struct BSTNode *pNew = (struct BSTNode *)malloc(sizeof(struct BSTNode));if(NULL == pNew)exit(-1);pNew ->data = InsertVal;pNew ->pLchild = pNew ->pRchild = NULL;struct BSTNode *pTmp = NULL;while(NULL != pBST ){pTmp = pBST;if(pNew ->data < pBST ->data)pBST = pBST ->pLchild;elsepBST = pBST ->pRchild;}pNew->pParent = pTmp;if(NULL == pTmp)  //当树为空时,将插入节点的地址赋给根节点*pRoot = *pNew;else if(pNew ->data <= pTmp ->data)pTmp ->pLchild = pNew;elsepTmp ->pRchild = pNew;
}

6.删除二叉树中的元素

void DeleteBSTree(struct BSTNode *pBST,int DeleteVal)
{struct BSTNode *pTem = SearchBSTree(pBST,DeleteVal);if(pTem == NULL){printf("没有找到要删除的元素!\n");exit(-1);}if(NULL == pTem ->pLchild && NULL == pTem ->pRchild) //删除节点无左右孩子{if(pTem == pTem ->pParent ->pLchild)  //删除节点是其父节点的左孩子{pTem ->pParent ->pLchild = NULL;}else              //删除节点是其父节点的右孩子{pTem ->pParent ->pRchild =NULL;}free(pTem);pTem = NULL;}else if(NULL == pTem ->pLchild)    //删除节点无左孩子{if(pTem == pTem ->pParent ->pLchild)  //删除节点为其父节点的左孩子{pTem ->pParent ->pLchild = pTem ->pRchild;pTem ->pRchild ->pParent =pTem ->pParent;}else                                 //删除节点为其父节点的右孩子{pTem ->pParent ->pRchild = pTem ->pRchild;pTem ->pRchild ->pParent =pTem ->pParent;}free(pTem);pTem = NULL;}else if(NULL == pTem ->pRchild) //删除节点无右孩子{if(pTem == pTem ->pParent->pLchild)  //删除节点为其父节点的左孩子{pTem ->pParent ->pLchild = pTem ->pLchild;pTem ->pLchild ->pParent = pTem ->pParent;}else   //删除节点为其父节点的右孩子{pTem ->pParent ->pRchild = pTem ->pLchild;pTem ->pLchild ->pParent = pTem ->pParent;}free(pTem);pTem = NULL;}else    //删除节点有左右孩子,用删除节点左字树中的最大值或者右子树中最小值来代替删除节点//本例中用右子树中最小值来代替{struct BSTNode *pTial = pTem ->pRchild;while(NULL != pTial ->pLchild)  //查找右子树中的最小值{pTial = pTial ->pLchild;}if(pTem == pTial ->pParent)  //右子树中的最小值的父节点是删除节点{if(pTem == pTem ->pParent ->pLchild)  //删除节点为其父节点的左孩子{pTem ->pParent ->pLchild = pTial;pTial ->pLchild = pTem ->pLchild;pTem ->pLchild->pParent = pTial;}else{pTem ->pParent ->pRchild = pTial;pTial ->pLchild = pTem ->pLchild;pTem ->pLchild->pParent = pTial;}free(pTem);pTem = NULL;}else{pTial ->pRchild ->pParent = pTial ->pParent;pTial ->pParent ->pLchild = pTial ->pRchild;pTial ->pParent ->pParent = pTial;pTial ->pRchild = pTial ->pParent;pTial ->pLchild = pTem ->pLchild;pTem ->pLchild ->pParent = pTial;if(pTem == pTem ->pParent ->pLchild){pTem ->pParent ->pLchild = pTial;}elsepTem ->pParent ->pRchild = pTial;free(pTem);pTem = NULL;}}
}

7.创建一颗二叉搜索树

struct BSTNode *CreateBSTree(void)
{struct BSTNode * pA = (struct BSTNode *)malloc(sizeof(struct BSTNode));if(NULL == pA)exit(-1);struct BSTNode * pB= (struct BSTNode *)malloc(sizeof(struct BSTNode));if(NULL == pB)exit(-1);struct BSTNode * pC= (struct BSTNode *)malloc(sizeof(struct BSTNode));if(NULL == pC)exit(-1);struct BSTNode * pD= (struct BSTNode *)malloc(sizeof(struct BSTNode));if(NULL == pD)exit(-1);struct BSTNode * pE= (struct BSTNode *)malloc(sizeof(struct BSTNode));if(NULL == pE)exit(-1);struct BSTNode * pF= (struct BSTNode *)malloc(sizeof(struct BSTNode));if(NULL == pF)exit(-1);struct BSTNode * pG= (struct BSTNode *)malloc(sizeof(struct BSTNode));if(NULL == pG)exit(-1);struct BSTNode * pH= (struct BSTNode *)malloc(sizeof(struct BSTNode));if(NULL == pH)exit(-1);struct BSTNode * pI= (struct BSTNode *)malloc(sizeof(struct BSTNode));if(NULL == pI)exit(-1);struct BSTNode * pJ= (struct BSTNode *)malloc(sizeof(struct BSTNode));if(NULL == pJ)exit(-1);pA ->data = 4;pB ->data = 2;pC ->data = 7;pD ->data = 3;pE ->data = 6;pF ->data = 13;pG ->data = 5;pH ->data = 10;pI ->data = 14;pJ ->data = 11;pA ->pParent = NULL;pA ->pLchild = pB;pA ->pRchild = pC;pB ->pParent = pA;pB ->pLchild = NULL;pB ->pRchild = pD;pD ->pParent = pB;pD ->pLchild = pD ->pRchild = NULL;pC ->pParent = pA;pC ->pLchild = pE;pC ->pRchild = pF;pE ->pParent = pC;pE ->pLchild = pG;pE ->pRchild = NULL;pF ->pParent = pC;pF ->pRchild = pI;pF ->pLchild =pH;pG ->pParent = pE;pG ->pLchild = pG ->pRchild = NULL;pH ->pParent = pF;pH ->pLchild = NULL;pH ->pRchild = pJ;pI ->pParent = pF;pI ->pLchild = pI ->pRchild = NULL;pJ ->pParent = pH;pJ ->pLchild = pJ ->pRchild =NULL;return pA;
}

8.主函数

int main()
{int MinData,MaxData;struct BSTNode *pRoot;pRoot=CreateBSTree();//printf("先序遍历:\n");//PreTraverseBSTree(pRoot);printf("\n中序遍历:\n");InTraverseBSTree(pRoot);//printf("\n后续遍历:\n");//PostTraverseBSTree(pRoot);printf("\n查找的元素为: key = 5");struct BSTNode *pKeyNode = SearchBSTree(pRoot,5);if(NULL == pKeyNode)printf("查找失败!\n");elseprintf("\n查找成功,结点地址为:%p!",pKeyNode);struct BSTNode *pMinData = SearchMinBSTree(pRoot,&MinData);printf("\n最小值为:%d,其结点地址为:%p",MinData,pMinData);struct BSTNode *pMaxDate = SearchMaxBSTree(pRoot,&MaxData);printf("\n最大值为:%d,其结点地址为:%p",MaxData,pMaxDate);printf("\n插入的元素为: data = 10");InsertBSTree(pRoot,1); //插入元素printf("\n中序遍历:\n");InTraverseBSTree(pRoot);DeleteBSTree(pRoot,4);printf("\n中序遍历:\n");InTraverseBSTree(pRoot);return 0;
}

9.运行结果
中序遍历:
数据为:2,父节点地址为:00e11700
数据为:3,父节点地址为:00e11718
数据为:4,父节点地址为:00000000
数据为:7,父节点地址为:00e11700
数据为:6,父节点地址为:00e11730
数据为:5,父节点地址为:00e11760
数据为:13,父节点地址为:00e11730
数据为:10,父节点地址为:00e11778
数据为:11,父节点地址为:00e117a8
数据为:14,父节点地址为:00e11778

查找的元素为: key = 5
查找成功,结点地址为:00e11790!
最小值为:2,其结点地址为:00e11718
最大值为:14,其结点地址为:00e117c0
插入的元素为: data = 10
中序遍历:
数据为:2,父节点地址为:00e11700
数据为:1,父节点地址为:00e11718
数据为:3,父节点地址为:00e11718
数据为:4,父节点地址为:00000000
数据为:7,父节点地址为:00e11700
数据为:6,父节点地址为:00e11730
数据为:5,父节点地址为:00e11760
数据为:13,父节点地址为:00e11730
数据为:10,父节点地址为:00e11778
数据为:11,父节点地址为:00e117a8
数据为:14,父节点地址为:00e11778

中序遍历:
数据为:2,父节点地址为:00e11700
数据为:1,父节点地址为:00e11718
数据为:3,父节点地址为:00e11718
数据为:4,父节点地址为:00000000
数据为:10,父节点地址为:00e11778
数据为:6,父节点地址为:00e117a8
数据为:5,父节点地址为:00e11760
数据为:13,父节点地址为:00e117a8
数据为:11,父节点地址为:00e11778
数据为:14,父节点地址为:00e11778

利用C语言实现二叉搜索树的遍历、查找、插入、删除相关推荐

  1. 【数据结构笔记11】二叉搜索树,动态查找,删除操作

    本次笔记内容: 4.1.1 二叉搜索树及查找 4.1.2 二叉搜索树的插入 4.1.3 二叉搜索树的删除 文章目录 动态查找 什么是二叉搜索树(BST) 二叉树的操作 二叉搜索树的查找操作 二叉搜索树 ...

  2. C语言在二叉搜索树找到第k个最小元素(附完整源码)

    C语言在二叉搜索树找到第k个最小元素 C语言在二叉搜索树找到第k个最小元素完整源码(定义,实现,main函数测试) C语言在二叉搜索树找到第k个最小元素完整源码(定义,实现,main函数测试) #in ...

  3. leetcode 98. 验证二叉搜索树 递归遍历左右子树和中序遍历 c语言解法

    如题: 给定一个二叉树,判断其是否是一个有效的二叉搜索树. 假设一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数. 节点的右子树只包含大于当前节点的数. 所有左子树和右子树自身必须也是 ...

  4. 二叉搜索树的范围和c语言,LeetCode0938: 二叉搜索树的范围和

    描述: 给定二叉搜索树的根结点 root,返回 L 和 R(含)之间的所有结点的值的和. 二叉搜索树保证具有唯一的值. 示例 1: 输入:root = [10,5,15,3,7,null,18], L ...

  5. 利用单调栈判断二叉搜索树的后序遍历序列

    假设二叉搜索树长这样,他的异端前序遍历应该是 [5,6,2,3,1] 现在如果给出一个这样的数组,如何重建这课二叉搜索树? 首先 5 \ 6 然后来了2, 递增栈会一直递增, 6,5 这时候6,5全部 ...

  6. 刷题笔记(1) 一个序列是否为二叉搜索树的遍历结果

    1.输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出No.假设输入的数组的任意两个数字都互不相同. 二叉搜索树:具体定义:https://blog.csdn ...

  7. 二叉搜索树的创建、插入、遍历、删除

    二叉搜索树 本文主要记录自己完成学校课程布置的有关"二叉搜索树"的代码闯关题的代码和思路心得,部分内容有借鉴身边大佬,借鉴部分会有标注. 二叉搜索树的结构体定义 struct no ...

  8. 二叉树:二叉搜索树的创建和插入

    二叉搜索树又名二叉排序树. 大概简略的思维导图如下,方便记忆特性 基本二叉搜索树创建过程如下 /*数据结构如下*/ typedef struct tree {int data;struct tree ...

  9. 在二叉搜索树(BST)中查找第K个大的结点之非递归实现

    一个被广泛使用的面试题: 给定一个二叉搜索树,请找出其中的第K个大的结点. PS:我第一次在面试的时候被问到这个问题而且让我直接在白纸上写的时候,直接蒙圈了,因为没有刷题准备,所以就会有伤害.知耻而后 ...

最新文章

  1. Init进程和进程 ④
  2. 超专业解析!10分钟带你搞懂Linux中直接I/O原理
  3. 央视谈鸿蒙系统的优点,央视解释为什么华为鸿蒙系统不卡顿,本质上和iOS一样流畅...
  4. HTTP长连接、短连接
  5. PMcaff微课堂 | 洋葱淘elya妞,前百度UX Leader:独门创业经验,产品秘籍
  6. Building wheel for wrapt (setup.py) ... error的解决办法(图文)
  7. if、for、while、do while、switch (区别于if、while)解析
  8. ThinkPHP3.1快速入门(6)路由
  9. python爬取豆瓣电影top250_Python爬虫 - scrapy - 爬取豆瓣电影TOP250
  10. 吃豆人(luogu 7472/NOI Online 2021 普及组 T2)
  11. java xmpp openfire_搭建Xmpp服务器Openfire
  12. Android Learning:数据存储方案归纳与总结
  13. python perl正则表达式_python学习笔记(正则表达式)
  14. Python 标准库 —— os 路径(os.path)
  15. java后台开发必备的9大类基础工具,你集齐了?
  16. 为什么国内动漫制作多为3D动漫?3DMAX制作次时代建模主要是因为?
  17. 程序员都在用的电脑小技巧,一遍就学会,每天早下班一小时
  18. 你就是北上广深的树先生
  19. 【图解线性代数】第一章——线性代数的几何意义导读(思维导图)
  20. k3 wise组件服务器安装,金蝶 K3 WISE 中间层组件安装报错!

热门文章

  1. Docker三大核心之容器
  2. Android点9图片被放大的问题
  3. 厦门计算机中专学校,厦门有哪些中专学校
  4. Cholesterol-PEG-Maleimide|胆固醇-聚乙二醇-马来酰亚胺修饰蛋白用
  5. ASP.NET 缓存技术(一)——启用页面输出缓存
  6. 【活动推荐】2020中国DevOps社区峰会(成都站)
  7. SAP UI5 应用开发教程之一百零四 - SAP UI5 表格控件的支持复选(Multi-Select)以及如何用代码一次选中多个表格行项目
  8. 鸡尾酒排序算法c语言源代码,排序算法之鸡尾酒排序
  9. 【如何在自己的宿舍有一台幽灵主机?】关于如何合理配置外网透穿和进行System服务的编写、安装,同时添加局域网唤醒等的一次实践。
  10. 浅谈产品经理入门和学习路径