数据结构 --- c语言二叉搜索树(有序的树)
二叉搜索树基础
左边的孩子节点 < 父节点的值,右边孩子节点 > 父节点的值
每棵二叉搜索树的子树也是一棵二叉搜索树
10 充当根节点
18 > 根节点,应该放在根节点的右边;3 < 根节点,放在根节点的左边;8 首先与根节点相比较,8 < 根节点,所以应该放在根节点的左边;然后 8 与 3 比较,3 < 8,8 应该放在 3 的右边,持续构建即可
二叉搜索树的特性:中序遍历是一个有序序列,是从小到大排序的,2-3-4-7-8-10-12-18
一般情况下数据没有重复的,节点的键是唯一的,二叉搜索树可以存储任何类型的数据 → 为数据配建一个键即可
用递归法或非递归法遍历
一旦插入的数据有序,创建出来的二叉搜索树就会出现不平衡的状态,0-2-5-18,因此后面会延伸成平衡二叉树
构建数据类型
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>//二叉搜索树可以存储任何类型的数据
typedef struct
{int key; //给数据配建关键字char value[20]; //字符串类型数据
}DATA,*LPDATA;
树节点的结构体描述
typedef struct treeNode
{//数据DATA data; struct treeNode* LChild; //左子树指针struct treeNode* RChild; //右子树指针
}NODE,*LPNODE;
创建节点 ---> 把用户的数据变成一个节点
//传入数据
LPNODE createNode(DATA data)
{//动态内存申请LPNODE newNode = (LPNODE)malloc(sizeof(NODE)); assert(newNode);//给数据做初始化newNode->data = data;newNode->LChild = NULL;newNode->RChild = NULL;return newNode;
}
二叉搜索树的结构体描述 ---> 再封装方式
typedef struct binarySearchTree
{LPNODE root; //根节点int treeSize; //树的当前元素个数
}BST,*LPBST;
创建二叉搜索树 ---> 用结构体指针表示二叉搜索树
创建二叉搜索树也就是描述树的最初状态,刚开始没有节点,二叉搜索树为空
LPBST createBST()
{//动态内存申请LPBST tree = (LPBST)malloc(sizeof(BST)); assert(tree);//一开始树是空的tree->root = NULL; //元素个数是0tree->treeSize = 0;return tree;
}
万金油函数
刚开始没有节点为空
如果树为空返回 0,树不为空判断 treeSize 是否等于 0
注意条件:树不能为空,为空不能判断 NULL->treeSize
int size(LPBST tree)
{return tree->treeSize;
}
int empty(LPBST tree)
{ return tree==NULL?0:tree->treeSize == 0;
}
二叉搜索树的插入
pmove走到空的位置才能做插入,需要记录移动节点的父节点的值 prepmove,即 pmove 的前驱节点,当 pmove 走到空的位置的时候,插在移动节点的父节点 prepmove 的左子树或者右子树的位置
需要两个指针做插入操作
移动节点 pmove
移动节点的前驱节点 prepmove
怎么移动:根据节点中的数据去比较
插入3,10 > 3,当前节点的数据 > 要插入节点的数据,3 要插在当前节点的左边
//要插入的树 要插入的数据
void insertNode(LPBST tree, DATA data)
{LPNODE newNode = createNode(data); //1.把用户的数据变成一个节点 2.找合适的位置LPNODE pmove = tree->root; //定义一个移动的指针从树的根节点开始移动LPNODE prepmove = NULL; //记录父节点的值while (pmove != NULL) //根不等于空 做查找{prepmove = pmove; //记录前驱节点=当前位置if (pmove->data.key > data.key)//移动 {pmove = pmove->LChild; //当前节点的键>要插入节点的键 数据要往左边插}else if (pmove->data.key < data.key) {pmove = pmove->RChild; //当前节点的键<要插入节点的键 数据要往右边插}else {//相等的键采用覆盖的方式strcpy_s(pmove->data.value, 20, data.value);return;}}//退出循环 1.找到了合适的位置 2.没有进入循环//插在移动节点的前驱节点prepmove 的左边还是右边需要分类讨论if (tree->root == NULL) //树=空 循环一次都没有执行{tree->root = newNode; //单独处理 把新节点当作根节点}else //树!=空{//做插入 分析是插在prepmove 的左边还是右边->只需要判断它和插入元素的值即可if (prepmove->data.key > data.key) {prepmove->LChild = newNode;//当前节点的键>要插入节点的键 放在当前节点左边}else {prepmove->RChild = newNode;//当前节点的键<要插入节点的键 放在当前节点右边}}tree->treeSize++; //当前元素个数++
}
二叉搜索树的遍历 ---> 递归法遍历
打印元素的值与键值
void printNode(LPNODE curNode)
{printf("%d:%s\n", curNode->data.key, curNode->data.value); //打印数据
}
//要遍历的树
void midOrder(LPNODE tree)
{if (tree != NULL) {//左根右midOrder(tree->LChild);printNode(tree);midOrder(tree->RChild);}
}
//测试代码
int main()
{LPBST tree = createBST(); //创建二叉搜索树DATA data[8] = { 10,"张三",5,"李四",49,"王五",2,"小芳",18,"小黑",89,"小红",0,"小明",22,"小花" }; for (int i = 0; i < 8; i++) {insertNode(tree, data[i]); //插入数据}midOrder(tree->root);
}
/*输出*/
0:小明
2:小芳
5:李四
10:张三
18:小黑
22:小花
49:王五
89:小红
二叉搜索树的查找 ---> 二分查找
每次查找都可以一分为二
找元素 7,首先从根节点开始找,由于7<10,根节点的右子树不用找,只需要在根节点的左子树找,由于 7 > 3,3 的左子树不用找,只需要找 3 的右子树 . . .
//二分查找 要搜索的树 通过键来搜索
LPNODE searchBST(LPBST tree, int key)
{LPNODE pmove = tree->root; //定义一个移动的指针从根节点开始找while (pmove != NULL && pmove->data.key != key) //pmove!=NULL并且pmove->data.key!=指定key{//往下查找if (pmove->data.key > key) {pmove = pmove->LChild; //当前节点的键>要插入节点的键 要往左边找}else {pmove = pmove->RChild; //当前节点的键<要插入节点的键 要往右边找}}return pmove; //返回空表示未找到 找到了->返回查找到的结果
}//测试代码LPNODE result = searchBST(tree,18);printf("查找结果:"); //做判空处理后做查找//查找结果 18:小黑printNode(result);
二叉搜索树的删除
需要找到删除节点 和 删除节点的前驱节点(父节点),删除节点会影响到删除节点的前驱节点和后面的节点
左右子树的删除操作都是一样的,只研究左子树即可
只有一边的处理:判定要删除的节点在前驱节点的左边还是右边,把删除节点的左 | 右边连到原来节点的左 | 右边即可
注意两边都有节点的处理:删除78,从当前删除节点的左边拿节点 50 或者从当前删除节点的右边拿节点 80 都可以,假设下面还有节点,为了能够只做一次调整,需要把两条边的情况变成一条边的情况
如果从左边拿节点:从删除节点的 左子树中找最右边,这样就只有左边,如果有左边就变成一条边的情况 就是在剩下的子树中找一个最大的放上去
如果从右边拿节点:从删除节点的 右子树中找最左边 就是在剩下的子树中找一个最小的放上去
注意:删除 78 其实是需要删除两个节点,78 可以直接覆盖,对于 59 是左子树的最右边,把 59 挪上去覆盖78,要对 59 再做一次删除,59 的删除是只有一条边的情况:无论 59 左边连接了多少个节点,只需要判断是放在前驱节点 58 的左边还是右边即可
//要删除的树 通过键去做删除
void deleteNode(LPBST tree, int key)
{//No.1 查找删除节点 以及删除的节点的父节点LPNODE pmove = tree->root;if (pmove == NULL){printf("树为空,无法删除!");return;}LPNODE pmoveparent = NULL; //移动节点的父节点//!=NULL并且!=指定key 让它们往下走while (pmove != NULL && pmove->data.key != key){pmoveparent = pmove; //记录父节点if (pmove->data.key > key){pmove = pmove->LChild; //当前节点的数据>要插入数据的键 数据要往左边走}else if (pmove->data.key < key){pmove = pmove->RChild; //当前节点的数据<要插入数据的键 数据要往右边走}else //两者相等直接退出循环{break;}}//No.2//2.1 分析查找结果 做不同的删除if (pmove == NULL) {printf("没有找到指定位置无法删除\n");return;}//2.2 左右子树都健全的情况->需要把两条边的情况变成只有一条边的情况if (pmove->LChild != NULL && pmove->RChild != NULL) {LPNODE moveNode = pmove->LChild; //从删除节点的左|右子树开始移动 拿最大的[最右边]LPNODE moveNodeParent = pmove; //记录59的父节点//走到左子树的最右边while (moveNode->RChild != NULL) //移动节点的右子树不为空一直往右边走{moveNodeParent = moveNode; //记录父节点moveNode = moveNode->RChild; //移动}//创建的节点要替换删除节点功能->不是用直接修改数据的方式//创建的节点数据是要调整的节点数据 //创建新节点59替换原来节点78的功能 78的左边连到59的左边、78的右边连到59的右边LPNODE newNode = createNode(moveNode->data); //新节点的数据=原来的datanewNode->LChild = pmove->LChild; //新节点的左边=原来删除节点的左边newNode->RChild = pmove->RChild; //新节点的右边=原来删除节点的右边//分类讨论父节点是否存在,如果不存在说明删除节点是根节点if (pmoveparent == NULL) {tree->root = newNode; //需要改变根节点的位置}else if (pmove == pmoveparent->LChild) //要删除的节点在原来父节点的左边{pmoveparent->LChild = newNode; //新节点要成为原来父节点的左边}else {pmoveparent->RChild = newNode; //新节点要成为原来父节点的右边}//调整二叉树的位置->要删除的节点不再是pmove为了删除调整的节点59 改变一下指针的位置if (moveNodeParent == pmove) //位置没有变化,要删除的节点没有右边{pmoveparent = newNode;}else {pmoveparent = moveNodeParent; }free(pmove);pmove = moveNode;//依旧用pmove和pmoveparent来做调整节点的删除}//调整为只有一边的情况LPNODE sNode = NULL;if (pmove->LChild != NULL) {sNode = pmove->LChild; //!=NULL 存在左边 记录要调整节点的左边 }else {sNode = pmove->RChild; //pmove是要调整的节点 把要调整节点的孩子节点记录下来} //删除的时候只需要把父节点指向sNode即可if (tree->root == pmove) //判断根节点是否==要调整节点{tree->root = sNode; }else {if (pmove == pmoveparent->LChild) //判断要删除的节点是在其父节点的左边还是右边{pmoveparent->LChild = sNode; //放在调整的节点的父节点的左边}else {pmoveparent->RChild = sNode;}}free(pmove);tree->treeSize--;
}
//测试代码deleteNode(tree,49);printf("\n删除后的结果!.....\n");midOrder(tree->root);
/*输出*/
0:小明
2:小芳
5:李四
10:张三
18:小黑
22:小花
89:小红
数据结构 --- c语言二叉搜索树(有序的树)相关推荐
- C语言二叉搜索树返回key的树级(附完整源码)
C语言二叉搜索树返回key的树级 C语言二叉搜索树返回key的树级完整源码(定义,实现,main函数测试) C语言二叉搜索树返回key的树级完整源码(定义,实现,main函数测试) #include ...
- Suzy找到实习了吗 Day23 | 二叉树最后一节!669. 修剪二叉搜索树,108. 将有序数组转换为二叉搜索树,538. 把二叉搜索树转换为累加树
669. 修剪二叉搜索树 题目 给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high.通过修剪二叉搜索树,使得所有节点的值在[low, high]中.修剪树 不应该 改变保 ...
- 数据结构与算法:二叉搜索树
✨数据结构与算法:二叉搜索树
- 【数据结构与算法】之深入解析“把二叉搜索树转换为累加树”和“从二叉搜索树到更大和树”的求解思路与算法示例
一.题目要求 ① 把二叉搜索树转换为累加树 给出二叉搜索树的根节点,该树的节点值各不相同,请将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 no ...
- 种树:二叉树、二叉搜索树、AVL树、红黑树、哈夫曼树、B树、树与森林
虽然今天不是植树节,但是我今天想种树. 文章目录 树,什么是树? 二叉树 定义 二叉树的创建 二叉树的前中后序遍历 前序遍历: 中序遍历 后序遍历 已知前序.中序遍历结果,还原二叉树 已知后序.中序遍 ...
- 力扣538.把二叉搜索树转换为累加树
题目来源: 538.把二叉搜索树转换为累加树 题目: 给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中 ...
- [二叉树遍历|BST]leetcode 538 把二叉搜索树转换为累加树
[二叉树遍历|BST]leetcode 538 把二叉搜索树转换为累加树 1.题目 题目链接 给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater Tree) ...
- leetcode c++未初始化_LeetCode 力扣官方题解 | 538. 把二叉搜索树转换为累加树
力扣 538. 把二叉搜索树转换为累加树(点击查看题目) 力扣leetcode-cn.com 题目描述 给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater ...
- Leetcode 538. 把二叉搜索树转换为累加树 C++
Leetcode 538. 把二叉搜索树转换为累加树 题目 给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater Tree),使得每个节点的值是原来的节点值加 ...
最新文章
- c语言如何持续输入字符直到指定字符结束_《小白学C》第三章 常用输入输出函数...
- python知识点博客园_python零碎知识点一
- [转] HDU 题目分类
- python信号分析_Python频谱分析
- DCMTK:全局类型和常量定义
- 【转】独家教程:用PHP编写Android应用程序
- 最短路径之Floyd算法
- 银行委托第三方催收信用卡欠款,是合法吗?
- C语言程序设计实验最短路径,7最短路径C语言程序设计.pdf
- YBTOJ洛谷P2387: 魔法森林(LCT)
- xtrabackup mysql 5.1_mysql 5.1 选哪个 xtrabackup
- 利用阿里云LAMP环境搭建搭建wiki知识库
- User Agent跨站攻击
- 动手学习深度学习的PDF电子版
- NeurIPS、COLING顶会亮点有哪些 | 一周学术精选
- 智能优化算法:象群算法-附代码
- 解决方法:Linux装完显卡驱动后分辨率显示不正常
- wav怎么转换成mp3?
- [高通SDM450][Android9.0]CTA认证--Android6.0以下应用默认不授权
- useCallback包裹函数,但是使用到的外部变量一直是最开始的值
热门文章
- 工程师不仅能调试自动化立体库,还能用PLC“不务正业”做这些“骚”操作
- dzzoffice二次开发,支持wps,et格式
- Linux - 第8节 - 进程信号
- 南邮攻防平台writeup(misc篇)1【图种】
- 如何构建古生物化石的系统发育树
- 网店版重生系列:因为webwork.configuration.xml.reload遭遇Web应用性能测试瓶颈
- Python网络爬虫——爬取网站图片小工具
- 使用FAXCOMEXLib与Windows XP计算机在.Net 2005 2.0版中发送传真
- 计算机学院运动会方阵策划案,运动会方阵策划案(图文)教学文案
- AI龙头商汤科技跌进元宇宙的运行轨迹