当前位置: 首页 > news >正文

完整教程:嵌入式数据结构笔记七——二叉树

文章目录

  • 前言
  • 一、概念:
  • 二、树形结构:
  • 三、二叉树:
  • 四、完全二叉树的操作:
    • 1.节点定义
    • 2.创建完全二叉树
    • 3. 二叉树深度优先遍历(递归实现)
    • 4. 二叉树广度优先遍历
    • 5. 创建非完全二叉树
    • 6. 获得树的高度
    • 7. 二叉树深度优先遍历(非递归实现)
  • 重点


前言

Linux系统是一种什么结构?队列可以在什么场景下用?


正文内容:

一、概念:

二、树形结构:

在这里插入图片描述

  • 节点:组成树形结构的一个小的单元称为节点
    • 根节点:只有后继,没有前驱
    • 分支节点:既有前驱,又有后继
    • 叶子节点:只有前驱,没有后继
  • 前驱(祖先):由哪个节点可以访问到该节点
  • 后继(子孙):该节点可以后续访问到哪些节点
  • 度:后继节点的个数
  • 层:根节点层数为1,后续每引申出的一个节点就在该节点层数上+1
  • 树的层树:树的层数由层数最高的节点对应的层数表示树的层数
  • 高度:节点高度是由该节点到最远的叶子节点的距离表示该节点高度
  • 深度:节点深度是由该节点到根节点的距离表示节点深度

三、二叉树:

  • 树形结构中的所有节点度数最大为2,称为二叉树
  • 二叉树节点类型:
    • 叶子节点
    • 只有左孩子
    • 只有右孩子
    • 左右孩子都有

在这里插入图片描述

  • 满二叉树——所有叶子节点均在同一层,且每层节点个数均为最大值。
    • 满二叉树第k层节点有2k−12^{k-1}2k1
    • 满二叉树前k层节点有2k−12^k-12k1

在这里插入图片描述

  • 完全二叉树——二叉树的编号(如果节点编号为n,左孩子编号:2n,右孩子编号为:2n+1)展开后是连续的,称为完全二叉树。

在这里插入图片描述

  • 完全二叉树的遍历形式:
    • 深度优先遍历(DFS)
      • 前序遍历(先序遍历):根左右
      • 中序遍历:左根右
      • 后序遍历:左右根
        • 已知中序后序遍历求先序——画图
    • 广度优先遍历(BFS)
      • 层序遍历:逐层从左到右依次遍历
        • 下图层序遍历的顺序为ABCDEFGH在这里插入图片描述

四、完全二叉树的操作:

1.节点定义

在这里插入图片描述

/* 二叉树节点类型 */
typedef struct node {
int no;
//编号
struct node *pleftchild;
//左子树根节点地址
struct node *prightchild;
//右子树根节点地址
}treenode;

2.创建完全二叉树

  • 通过函数递归完成完全二叉树的创建
    • 申请节点空间
    • 存放数据编号
    • 如果存在左子树递归创建左子树
    • 如果存在右子树递归创建右子树
      在这里插入图片描述

代码如下:

/* 完全二叉树的创建 */
treenode *create_complete_btree(int startno, int endno)
{
treenode *ptmpnode = NULL;
ptmpnode = malloc(sizeof(treenode));
if(NULL == ptmpnode)
{
perror("fail to malloc");
return NULL;
}
ptmpnode->no = startno;
ptmpnode->pleftchild = ptmpnode->prightchild = NULL;
if (2*startno <= endno)
{
ptmpnode->pleftchild = create_complete_btree(2*startno, endno);
}
if (2*startno + 1 <= endno)
{
ptmpnode->prightchild = create_complete_btree(2*startno+1,endno);
}
return ptmpnode;
}

3. 二叉树深度优先遍历(递归实现)

  • 前序遍历:
/* 前序遍历 */
int preorder_btree(treenode *proot)
{
printf("%d ", proot->no);
if (proot->pleftchild != NULL)
{
preorder_btree(proot->pleftchild);
}
if (proot->prightchild != NULL)
{
preorder_btree(proot->prightchild);
}
return 0;
}
  • 中序遍历:
/* 中序遍历 */
int inorder_btree(treenode *proot)
{
if (proot->pleftchild != NULL)
{
inorder_btree(proot->pleftchild);
}
printf("%d ", proot->no);
if (proot->prightchild != NULL)
{
inorder_btree(proot->prightchild);
}
return 0;
}
  • 后序遍历:
/* 后序遍历 */
int postorder_btree(treenode *proot)
{
if (proot->pleftchild != NULL)
{
postorder_btree(proot->pleftchild);
}
if (proot->prightchild != NULL)
{
postorder_btree(proot->prightchild);
}
printf("%d ", proot->no);
return 0;
}
  • 二叉树的销毁:
/* 销毁完全二叉树 */
int destroy_btree(treenode *proot)
{
if (proot->pleftchild)
{
destroy_btree(proot->pleftchild);
}
if (proot->prightchild)
{
destroy_btree(proot->prightchild);
}
free(proot);
return 0;
}

4. 二叉树广度优先遍历

  • 层序遍历:
    在这里插入图片描述

代码如下:

/* 层序遍历 */
int layoutorder_btree(treenode* proot)
{
linkqueue *ptmpqueue = create_empty_linkqueue();
treenode *ptmpnode = NULL;
//队列中存放的数据类型是 treenode* 型
enter_linkqueue(ptmpqueue, proot);
while(!is_empty_linkqueue(ptmpqueue))
{
ptmpnode = exit_linkqueue(ptmpqueue);
printf("%d ",ptmpnode->no);
if(ptmpnode->pleftchild != NULL)
{
enter_linkqueue(ptmpqueue, ptmpnode->pleftchild);
}
if(ptmpnode->prightchild != NULL)
{
enter_linkqueue(ptmpqueue, ptmpnode->prightchild);
}
}
destory_linkqueue(&ptmpqueue);
return 0;
}

5. 创建非完全二叉树

  • 非完全二叉树,每个结构不一定相同,所以需要从终端接收用户输入决定二叉树的创建
    在这里插入图片描述

代码如下:

/* 创建非完全二叉树 */
treenode *create_btree(void)
{
char ch = 0;
treenode *ptmpnode = NULL;
scanf(" %c", &ch);
if ('#' == ch)
{
return NULL;
}
ptmpnode = malloc(sizeof(treenode));
if (NULL == ptmpnode)
{
perror("fail to malloc");
return NULL;
}
//在节点定义中加入成员:char data;
ptmpnode->data = ch;
ptmpnode->pleftchild = create_btree();
ptmpnode->prightchild = create_btree();
return ptmpnode;
}

6. 获得树的高度

/* 获得树的高度 */
int get_bintree_height(treenode *proot)
{
int leftheight = 0;
int rightheight = 0;
if (NULL == proot)// 递归终止条件
{
return 0;
}
leftheight = get_bintree_height(proot->pleftchild);
// 递归计算左子树的高度 
rightheight = get_bintree_height(proot->prightchild);
// 递归计算右子树的高度 
// 返回左右子树中较大的高度 + 1
return (leftheight > rightheight ? leftheight : rightheight) + 1;
}

在这里插入图片描述

  • 递归调用树形图:
    在这里插入图片描述

7. 二叉树深度优先遍历(非递归实现)

在这里插入图片描述

  • 前序遍历:
/* 非递归前序遍历 */
int preorder_btree_bystack(treenode *proot)
{
linkstack *ptmpstack = NULL;
treenode *ptmpnode = NULL;
ptmpstack = create_empty_linkstack();
ptmpnode = proot;
while (1)
{
while (ptmpnode != NULL)
{
printf("%c ", ptmpnode->data);
push_linkstack(ptmpstack, ptmpnode);
ptmpnode = ptmpnode->pleftchild;
}
if (is_empty_linkstack(ptmpstack))
{
break;
}
ptmpnode = pop_linkstack(ptmpstack);
//回溯
ptmpnode = ptmpnode->prightchild;
}
return 0;
}
  • 中序遍历:
/* 非递归中序遍历 */
int inorder_btree_bystack(treenode *proot)
{
linkstack *ptmpstack = NULL;
treenode *ptmpnode = NULL;
ptmpstack = create_empty_linkstack();
ptmpnode = proot;
while (1)
{
while (ptmpnode != NULL)
{
push_linkstack(ptmpstack, ptmpnode);
ptmpnode = ptmpnode->pleftchild;
}
if (is_empty_linkstack(ptmpstack))
{
break;
}
ptmpnode = pop_linkstack(ptmpstack);
//回溯
printf("%c ", ptmpnode->data);
ptmpnode = ptmpnode->prightchild;
}
return 0;
}
  • 后序遍历:
    • 因为最后打印根节点,所以根节点需要2次入栈
    • 第一次入栈,是为了出栈时找到该节点的右孩子,找到右孩子后,继续将节点入栈
    • 第二次入栈,是为了打印该节点
/* 非递归后序遍历 */
int postorder_btree_bystack(treenode *proot)
{
linkstack *ptmpstack = NULL;
treenode *ptmpnode = NULL;
ptmpstack = create_empty_linkstack();
ptmpnode = proot;
while (1)
{
while (ptmpnode != NULL)
{
ptmpnode->flag = 1;
//在节点定义中加入成员:int flag;
push_linkstack(ptmpstack, ptmpnode);
ptmpnode = ptmpnode->pleftchild;
}
if (is_empty_linkstack(ptmpstack))
{
break;
}
ptmpnode = pop_linkstack(ptmpstack);
if (1 == ptmpnode->flag)
{
ptmpnode->flag = 0;
push_linkstack(ptmpstack, ptmpnode);
ptmpnode = ptmpnode->prightchild;
}
else if (0 == ptmpnode->flag)
{
printf("%c ", ptmpnode->data);
ptmpnode = NULL;
//正确回溯到上一个节点
}
}
return 0;
}

重点

  • 深度优先遍历(DFS)
  • 广度优先遍历(BFS)
http://www.jsqmd.com/news/2773/

相关文章:

  • 51单片机-驱动DS1302时钟芯片模块教程 - 实践
  • JVM 类加载器详解 - 实践
  • Unity小游戏接入抖音敏感词检测 - 指南
  • SQLite的并发问题
  • 域渗透靶场-vulntarget-a综合靶场
  • 数组和链表读取、插入、删除以及查找的区别
  • day 09 课程
  • 在K8S中,日志分析工具有哪些可以与K8S集群通讯?
  • 在K8S中,网络通信模式有哪些?
  • 一文教你搞定PASS 2025:样本量计算神器安装到使用全流程
  • React 18.2中采用React Router 6.4
  • 题解:AT_abc257_h [ABC257Ex] Dice Sum 2
  • ClickHouse UPDATE 机制详解 - 若
  • Jetpack Room 从入门到精通 - 实践
  • ClickHouse index_granularity 详解 - 若
  • PADS笔记
  • 【2025最新教程】Claude Code国内使用_保姆级新手安装使用教程_最强AI编程工具
  • 如何计算sequence粒度的负载均衡损失 - 教程
  • P13885 [蓝桥杯 2023 省 Java/Python A] 反异或 01 串
  • clickhouse轻量级更新 - 若
  • 西电PCB设计指南第3章学习笔记
  • Vitrualbox、kali、metaspolitable2下载安装
  • LazyLLM端到端实战:用RAG+Agent实现自动出题与学习计划的个性化学习助手智能体
  • 补充图
  • 域名+邮件推送+事件总线=实现每天定时邮件!
  • llm入门环境
  • FLASH空间划分/存储数据至指定CODEFLASH位置
  • 深入解析:【C语言代码】数组排序
  • SOOMAL 降噪数据表
  • 案例分享|借助IronPDF IronOCR,打造医疗等行业的智能化解决方案