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


前言

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


正文内容:

一、概念:

  • 线性结构:描述数据一对一的关系(表)
  • 非线性结构:描述数据一对多(树)、多对多(图)的关系

二、树形结构:

在这里插入图片描述

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

三、二叉树:

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

在这里插入图片描述

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

在这里插入图片描述

  • 完全二叉树——二叉树的编号(如果节点编号为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)
posted @ 2025-09-24 12:14  wzzkaifa  阅读(35)  评论(0)    收藏  举报