二叉搜索树基础

  • 左边的孩子节点 < 父节点的值,右边孩子节点 > 父节点的值

  • 每棵二叉搜索树的子树也是一棵二叉搜索树

  • 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语言二叉搜索树(有序的树)相关推荐

  1. C语言二叉搜索树返回key的树级(附完整源码)

    C语言二叉搜索树返回key的树级 C语言二叉搜索树返回key的树级完整源码(定义,实现,main函数测试) C语言二叉搜索树返回key的树级完整源码(定义,实现,main函数测试) #include ...

  2. Suzy找到实习了吗 Day23 | 二叉树最后一节!669. 修剪二叉搜索树,108. 将有序数组转换为二叉搜索树,538. 把二叉搜索树转换为累加树

    669. 修剪二叉搜索树 题目 给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high.通过修剪二叉搜索树,使得所有节点的值在[low, high]中.修剪树 不应该 改变保 ...

  3. 数据结构与算法:二叉搜索树

    ✨数据结构与算法:二叉搜索树

  4. 【数据结构与算法】之深入解析“把二叉搜索树转换为累加树”和“从二叉搜索树到更大和树”的求解思路与算法示例

    一.题目要求 ① 把二叉搜索树转换为累加树 给出二叉搜索树的根节点,该树的节点值各不相同,请将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 no ...

  5. 种树:二叉树、二叉搜索树、AVL树、红黑树、哈夫曼树、B树、树与森林

    虽然今天不是植树节,但是我今天想种树. 文章目录 树,什么是树? 二叉树 定义 二叉树的创建 二叉树的前中后序遍历 前序遍历: 中序遍历 后序遍历 已知前序.中序遍历结果,还原二叉树 已知后序.中序遍 ...

  6. 力扣538.把二叉搜索树转换为累加树

    题目来源: 538.把二叉搜索树转换为累加树 题目: 给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中 ...

  7. [二叉树遍历|BST]leetcode 538 把二叉搜索树转换为累加树

    [二叉树遍历|BST]leetcode 538 把二叉搜索树转换为累加树 1.题目 题目链接 给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater Tree) ...

  8. leetcode c++未初始化_LeetCode 力扣官方题解 | 538. 把二叉搜索树转换为累加树

    力扣 538. 把二叉搜索树转换为累加树(点击查看题目) 力扣​leetcode-cn.com 题目描述 给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater ...

  9. Leetcode 538. 把二叉搜索树转换为累加树 C++

    Leetcode 538. 把二叉搜索树转换为累加树 题目 给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater Tree),使得每个节点的值是原来的节点值加 ...

最新文章

  1. c语言如何持续输入字符直到指定字符结束_《小白学C》第三章 常用输入输出函数...
  2. python知识点博客园_python零碎知识点一
  3. [转] HDU 题目分类
  4. python信号分析_Python频谱分析
  5. DCMTK:全局类型和常量定义
  6. 【转】独家教程:用PHP编写Android应用程序
  7. 最短路径之Floyd算法
  8. 银行委托第三方催收信用卡欠款,是合法吗?
  9. C语言程序设计实验最短路径,7最短路径C语言程序设计.pdf
  10. YBTOJ洛谷P2387: 魔法森林(LCT)
  11. xtrabackup mysql 5.1_mysql 5.1 选哪个 xtrabackup
  12. 利用阿里云LAMP环境搭建搭建wiki知识库
  13. User Agent跨站攻击
  14. 动手学习深度学习的PDF电子版
  15. NeurIPS、COLING顶会亮点有哪些 | 一周学术精选
  16. 智能优化算法:象群算法-附代码
  17. 解决方法:Linux装完显卡驱动后分辨率显示不正常
  18. wav怎么转换成mp3?
  19. [高通SDM450][Android9.0]CTA认证--Android6.0以下应用默认不授权
  20. useCallback包裹函数,但是使用到的外部变量一直是最开始的值

热门文章

  1. 工程师不仅能调试自动化立体库,还能用PLC“不务正业”做这些“骚”操作
  2. dzzoffice二次开发,支持wps,et格式
  3. Linux - 第8节 - 进程信号
  4. 南邮攻防平台writeup(misc篇)1【图种】
  5. 如何构建古生物化石的系统发育树
  6. 网店版重生系列:因为webwork.configuration.xml.reload遭遇Web应用性能测试瓶颈
  7. Python网络爬虫——爬取网站图片小工具
  8. 使用FAXCOMEXLib与Windows XP计算机在.Net 2005 2.0版中发送传真
  9. 计算机学院运动会方阵策划案,运动会方阵策划案(图文)教学文案
  10. AI龙头商汤科技跌进元宇宙的运行轨迹