二叉树的链式结构

简介: 二叉树的链式结构

前言

Hello,友友们,小编将继续重新开始数据结构的学习,前面讲解了堆的部分知识,今天将讲解二叉树的链式结构的部分内容。

1.概念回顾与新增

二叉树是一种数据结构,其中每个节点最多有两个子节点,分别是左子节点和右子节点。二叉树的链式结构表示是使用指针(或引用)来连接节点,形成树形结构。每个节点包含一个数据元素和两个指向子节点的指针。

2.简单创建二叉树

分为节点的定义,创建节点,创建树

下面我们将简单的手撕一个二叉树:

typedef struct BTnode {
  int val;
  struct BTnode* left;
  struct BTnode* right;
}Node;
 
//节点创建
Node* BuyNode(int x) {
  Node* node = (Node*)malloc(sizeof(Node));
  if (node == NULL) {
    perror("node fail");
    return NULL;
  }
  node->val = x;
  node->left = NULL;
  node->right = NULL;
  return node;
}
//树的创建
Node* CreatTree() {
  
    Node* node1 = BuyNode(1);
    Node* node2 = BuyNode(2);
    Node* node3 = BuyNode(3);
    Node* node4 = BuyNode(4);
    Node* node5 = BuyNode(5);
    Node* node6 = BuyNode(6);
 
    node1->left = node2;
    node1->right = node4;
    node2->left = node3;
    node4->left = node5;
    node4->right = node6;
    return node1;
}

注意:上述代码并不是创建二叉树的方式,真正创建二叉树方式后序详解重点讲解。

二叉树建立过后,接下来我们要进行二叉树的遍历操作

3.二叉树的遍历

所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的结点进行相应的操作,并且每个结点只操作一次。访问结点所做的操作依赖于具体的应用问题。 遍历是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。

按照规则,二叉树的遍历有: 前序 / 中序 / 后序的递归结构遍历

1. 前序遍历 (Preorder Traversal 亦称先序遍历 )—— 访问根结点的操作发生在遍历其左右子树之前。

2. 中序遍历 (Inorder Traversal)—— 访问根结点的操作发生在遍历其左右子树之中(间)。

3. 后序遍历 (Postorder Traversal)—— 访问根结点的操作发生在遍历其左右子树之后。

由于被访问的结点必是某子树的根, 所以 N(Node )、 L(Left subtree )和 R(Right subtree )又可解释为, 根的左子树和根的右子树 NLR LNR LRN 分别又称为先根遍历、中根遍历和后根遍历。

注意:为了方便理解,我们将空节点都视作为NULL

3.1前序遍历

代码:

void PreOrder(Node* root) {
  if (root == NULL) {
    printf("N ");
    return;
  }
  printf("%d ", root->val);
  PreOrder(root->left);
  PreOrder(root->right);
 
}

递归图解:

代码递归理解:

运行结果:1 2 3 N N N 4 5 N N 6 N N

注意:中序和后序与前序的递归展开图类似,小编就不在展示了。

3.2中序遍历

void InOrder(Node* root) {
  if (root == NULL) {
    printf("N ");
    return;
  }
  InOrder(root->left);
  printf("%d ", root->val);
    InOrder(root->right);
 
}

运行结果:N 3 N 2 N 1 N 5 N 4 N 6 N

3.3后序遍历

void PostOrder(Node* root) {
  if (root == NULL) {
    printf("N ");
    return;
  }
  PostOrder(root->left);
  PostOrder(root->right);
  printf("%d ", root->val);
 
}

运行结果:N N 3 N 2 N N 5 N N 6 4 1

3.4层序遍历

层序遍历 :除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根结点所在层数为1 ,层序遍历就是从所在二叉树的根结点出发,首先访问第一层的树根结点,然后从左到右访问第 2 层上的结点,接着是第三层的结点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。

层序遍历较为复杂,这里我们采用队列的方式来实现层序遍历。

这里我们简单的用动态数组实现队列,包括了队列的初始化,入队出队判空的操作。

3.4.1队列的实现
// 队列结构
typedef struct Queue {
  Node* data[MAX];
  int front;
  int rear;
} Queue;
 
// 初始化队列
void initQueue(Queue* q) {
  q->front = 0;
  q->rear = 0;
}
 
// 入队
void enqueue(Queue* q, Node* node) {
  if ((q->rear + 1) % MAX == q->front) {
    printf("Queue is full\n");
    return;
  }
  q->data[q->rear] = node;
  q->rear = (q->rear + 1) % MAX;
}
 
// 出队
Node* dequeue(Queue* q) {
  if (q->front == q->rear) {
    printf("Queue is empty\n");
    return NULL;
  }
  Node* node = q->data[q->front];
  q->front = (q->front + 1) % MAX;
  return node;
}
 
// 判断队列是否为空
int isEmpty(Queue* q) {
  return q->front == q->rear;
}
3.4.2层序遍历实现

从根节点开始,将每个节点的值打印出来,并依次将其左子节点和右子节点加入队列。

// 层序遍历函数
void levelOrder(Node* root) {
  if (root == NULL) {
    return;
  }
 
  Queue q;
  initQueue(&q);
  enqueue(&q, root);
 
  while (!isEmpty(&q)) {
    Node* node = dequeue(&q);
    printf("%d ", node->val);
 
    if (node->left) {
      enqueue(&q, node->left);
    }
    if (node->right) {
      enqueue(&q, node->right);
    }
  }
}

3.5主函数测试代码

int main() {
  Node* root = CreatTree();
  PreOrder(root);
  printf("\n");
  InOrder(root);
  printf("\n");
  PostOrder(root);
  printf("\n");
  levelOrder(root);
  return 0;
}

运行结果展示:

4.遍历相关选择练习

1. 某完全二叉树按层次输出(同一层从左到右)的序列为 ABCDEFGH 。该完全二叉树的前序序列为( A)

A .    ABDHECFG

B.    ABCDEFGH

C.    HDBEAFCG

D.    HDEBFGCA

2. 二叉树的先序遍历和中序遍历如下:先序遍历: EFHIGJK; 中序遍历: HFIEJKG. 则二叉树根结点为(A)

A .  E                        B.   F                      C.   G                          D.   H

3. 设一课二叉树的中序遍历序列: badce ,后序遍历序列: bdeca ,则二叉树前序遍历序列为(D)

A. adbce                   B. decab                C. debac                    D. abcde

4. 某二叉树的后序遍历序列与中序遍历序列相同,均为 ABCDEF ,则按层次输出(同一层从左到右)的序列 为(A)

A. FEDCBA

B. CBAFED

C. DEFCBA

D. ABCDEF


相关文章
|
21天前
|
人工智能 安全 Cloud Native
OpenClaw:开源AI Agent框架架构解析与云原生部署实践
OpenClaw是2026年热门开源AI Agent框架,将大模型从“对话式”升级为“行动式”,支持自主执行、四层记忆、多工具调用与跨平台通信。本文解析其分层架构(Gateway/Agent Runtime/Skill系统等),并提供阿里云ECS生产级部署方案,兼顾安全加固与云原生实践。(239字)
|
安全 JavaScript
any和unknown有何区别?
any和unknown有何区别?
516 1
|
人工智能 API 决策智能
Modelscope结合α-UMi:基于Modelscope的多模型协作Agent
基于单个开源小模型的工具调用Agent,由于模型容量和预训练能力获取的限制,无法在推理和规划、工具调用、回复生成等任务上同时获得比肩大模型等性能。
|
人工智能 NoSQL 定位技术
标准地图的矢量模板,ArcGIS可打开
标准地图的矢量模板,ArcGIS可打开
573 0
|
2月前
|
人工智能 Linux API
OpenClaw封神玩法:数字人形象声音克隆+多端部署(阿里云本地)与API配置实战完整教程
2026年,OpenClaw(Clawdbot)的玩法迎来颠覆性升级——通过集成数字人技能,实现形象克隆、声音克隆与数字人视频生成的全流程自动化,让AI助手从“文字交互”跃迁至“可视化语音交互”。无论是用个人照片生成专属数字人播报,还是克隆明星、名人音色制作创意视频,甚至复刻抖音爆款内容,OpenClaw都能一键完成。想要解锁这一高阶玩法,需先完成基础部署与大模型API对接,再集成数字人技能包。本文将详细拆解2026年OpenClaw的阿里云部署、本地MacOS/Linux/Windows11全系统部署流程,完成阿里云百炼Coding Plan免费API配置,最后手把手教你搭建数字人克隆技能,
1885 1
|
运维 监控 Serverless
一键开启 GPU 闲置模式,基于函数计算低成本部署 Google Gemma 模型服务
本文介绍如何使用函数计算 GPU 实例闲置模式低成本、快速的部署 Google Gemma 模型服务。
165453 58
|
数据采集 存储 调度
Scrapy:高效的Python网络爬虫框架
在信息时代,数据的获取和分析已经成为了一项重要的技能。而网络爬虫则是实现数据采集的一种常用手段。Scrapy作为一个高效、灵活的Python网络爬虫框架,其具备强大的扩展性、高度的可配置性以及良好的兼容性。本文将从Scrapy的概念入手,介绍其基本原理、使用方法以及实际应用案例。
|
Web App开发 编解码 JavaScript
【Vue篇】Vue 项目下载、介绍(详细版)
【Vue篇】Vue 项目下载、介绍(详细版)
303 3
|
数据采集 存储 数据可视化
【python】python学生学科成绩分析(源码+数据+报告)【独一无二】
【python】python学生学科成绩分析(源码+数据+报告)【独一无二】
|
IDE Java 开发工具
推荐10款实用且颜值高的在线代码编辑器
推荐10款实用且颜值高的在线代码编辑器
1117 0

热门文章

最新文章