【数据结构】树与二叉树(廿三):树和森林的遍历——层次遍历(LevelOrder)

文章目录

  • 5.3.1 树的存储结构
    • 5. 左儿子右兄弟链接结构
  • 5.3.2 获取结点的算法
  • 5.3.3 树和森林的遍历
    • 1. 先根遍历(递归、非递归)
    • 2. 后根遍历(递归、非递归)
    • 3. 森林的遍历
    • 4. 层次遍历
      • a. 算法LevelOrder
      • b. 算法解读
      • c. 时间复杂度
      • d.代码实现
        • 层次遍历(levelOrder)
        • 初始化队列(initQueue)
        • 入队列(enqueue)
        • 出队列(dequeue)
      • 5. 代码整合

5.3.1 树的存储结构

5. 左儿子右兄弟链接结构

【数据结构】树与二叉树(十九):树的存储结构——左儿子右兄弟链接结构(树、森林与二叉树的转化)
  左儿子右兄弟链接结构通过使用每个节点的三个域(FirstChild、Data、NextBrother)来构建一棵树,同时使得树具有二叉树的性质。具体来说,每个节点包含以下信息:

  1. FirstChild: 存放指向该节点的大儿子(最左边的子节点)的指针。这个指针使得我们可以迅速找到一个节点的第一个子节点。
  2. Data: 存放节点的数据。
  3. NextBrother: 存放指向该节点的大兄弟(同一层中右边的兄弟节点)的指针。这个指针使得我们可以在同一层中迅速找到节点的下一个兄弟节点。

  通过这样的结构,整棵树可以用左儿子右兄弟链接结构表示成一棵二叉树。这种表示方式有时候被用于一些特殊的树结构,例如二叉树、二叉树的森林等。这种结构的优点之一是它更紧凑地表示树,而不需要额外的指针来表示兄弟关系。
在这里插入图片描述

   A
  /|\
 B C D
  / \
 E   F
A
|
B -- C -- D
     |
     E -- F

即:

      A
     / 
    B   
    \
	  C
  	 / \ 
  	E   D
  	 \
  	  F

在这里插入图片描述

5.3.2 获取结点的算法

【数据结构】树与二叉树(二十):树获取大儿子、大兄弟结点的算法(GFC、GNB)

5.3.3 树和森林的遍历

【数据结构】树与二叉树(七):二叉树的遍历(先序、中序、后序及其C语言实现)

1. 先根遍历(递归、非递归)

在这里插入图片描述

【数据结构】树与二叉树(廿一):树和森林的遍历——先根遍历(递归算法PreOrder、非递归算法NPO)

2. 后根遍历(递归、非递归)

在这里插入图片描述

【数据结构】树与二叉树(廿二):树和森林的遍历——后根遍历(递归算法PostOrder、非递归算法NPO)

3. 森林的遍历

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4. 层次遍历

  树和森林层次遍历按层数由小到大,即从第0层开始逐层向下,同层中由左到右的次序访问所有结点。
在这里插入图片描述

a. 算法LevelOrder

在这里插入图片描述

b. 算法解读

  首先,创建一个队列Q,并将根指针t入队列Q中。然后,进入一个循环,只要队列Q非空,就执行以下操作:

  1. 将队首元素p出队列Q。
  2. 打印节点p的数据。
  3. 如果节点p有左子节点,则将左子节点入队列Q。
  4. 将节点p的右兄弟节点赋值给p,继续遍历下一个节点。

  LevelOrder算法通过队列的先进先出特性,确保按照从上到下、从左到右的顺序遍历二叉树的节点。

c. 时间复杂度

  在层次遍历中,每个结点都要进行1次入队、1次出队和1次访问,每次访问入队、出队和访问都是常数级的,因此,算法LevelOrder的时间复杂度为O(n)。

d.代码实现

层次遍历(levelOrder)
void LevelOrder(TreeNode* root) {
    if (root == NULL) {
        return;
    }

    Queue queue;
    initQueue(&queue);

    enqueue(&queue, root);

    while (queue.front != NULL) {
        TreeNode* p = dequeue(&queue);

        while (p != NULL) {
            // 访问当前结点
            printf("%c ", p->data);

            // 将大儿子结点入队列
            if (getFirstChild(p) != NULL) {
                enqueue(&queue, getFirstChild(p));
            }

            // 移动到下一个兄弟结点
            p = getNextBrother(p);
        }
    }
}

其中,队列操作详解:【数据结构】线性表(九)队列:链式队列及其基本操作(初始化、判空、入队、出队、存取队首元素)

初始化队列(initQueue)
void initQueue(Queue* q) {
    q->front = NULL;
    q->rear = NULL;
}

入队列(enqueue)
void enqueue(Queue* q, TreeNode* treeNode) {
    QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode));
    newNode->treeNode = treeNode;
    newNode->next = NULL;

    if (q->rear == NULL) {
        q->front = newNode;
        q->rear = newNode;
    } else {
        q->rear->next = newNode;
        q->rear = newNode;
    }
}

出队列(dequeue)
TreeNode* dequeue(Queue* q) {
    if (q->front == NULL) {
        return NULL; // 队列为空
    }

    TreeNode* treeNode = q->front->treeNode;
    QueueNode* temp = q->front;

    q->front = q->front->next;
    free(temp);

    if (q->front == NULL) {
        q->rear = NULL; // 队列为空
    }

    return treeNode;
}

5. 代码整合

#include <stdio.h>
#include <stdlib.h>

// 定义树节点
typedef struct TreeNode {
    char data;
    struct TreeNode* firstChild;
    struct TreeNode* nextBrother;
} TreeNode;

// 创建树节点
TreeNode* createNode(char data) {
    TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
    if (newNode != NULL) {
        newNode->data = data;
        newNode->firstChild = NULL;
        newNode->nextBrother = NULL;
    }
    return newNode;
}

// 释放树节点及其子树
void freeTree(TreeNode* root) {
    if (root != NULL) {
        freeTree(root->firstChild);
        freeTree(root->nextBrother);
        free(root);
    }
}

// 算法GFC:获取大儿子结点
TreeNode* getFirstChild(TreeNode* p) {
    if (p != NULL && p->firstChild != NULL) {
        return p->firstChild;
    }
    return NULL;
}

// 算法GNB:获取下一个兄弟结点
TreeNode* getNextBrother(TreeNode* p) {
    if (p != NULL && p->nextBrother != NULL) {
        return p->nextBrother;
    }
    return NULL;
}


// 队列结构
typedef struct QueueNode {
    TreeNode* treeNode;
    struct QueueNode* next;
} QueueNode;

typedef struct {
    QueueNode* front;
    QueueNode* rear;
} Queue;

// 初始化队列
void initQueue(Queue* q) {
    q->front = NULL;
    q->rear = NULL;
}

// 入队列
void enqueue(Queue* q, TreeNode* treeNode) {
    QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode));
    newNode->treeNode = treeNode;
    newNode->next = NULL;

    if (q->rear == NULL) {
        q->front = newNode;
        q->rear = newNode;
    } else {
        q->rear->next = newNode;
        q->rear = newNode;
    }
}

// 出队列
TreeNode* dequeue(Queue* q) {
    if (q->front == NULL) {
        return NULL; // 队列为空
    }

    TreeNode* treeNode = q->front->treeNode;
    QueueNode* temp = q->front;

    q->front = q->front->next;
    free(temp);

    if (q->front == NULL) {
        q->rear = NULL; // 队列为空
    }

    return treeNode;
}

// 层次遍历算法
void LevelOrder(TreeNode* root) {
    if (root == NULL) {
        return;
    }

    Queue queue;
    initQueue(&queue);

    enqueue(&queue, root);

    while (queue.front != NULL) {
        TreeNode* p = dequeue(&queue);

        while (p != NULL) {
            // 访问当前结点
            printf("%c ", p->data);

            // 将大儿子结点入队列
            if (getFirstChild(p) != NULL) {
                enqueue(&queue, getFirstChild(p));
            }

            // 移动到下一个兄弟结点
            p = getNextBrother(p);
        }
    }
}


int main() {
    // 构建左儿子右兄弟链接结构的树
    TreeNode* A = createNode('A');
    TreeNode* B = createNode('B');
    TreeNode* C = createNode('C');
    TreeNode* D = createNode('D');
    TreeNode* E = createNode('E');
    TreeNode* F = createNode('F');

    A->firstChild = B;
    B->nextBrother = C;
    C->nextBrother = D;
    C->firstChild = E;
    E->nextBrother = F;

    // 层次遍历算法
    printf("Level Order: \n");
    LevelOrder(A);
    printf("\n");
    
    freeTree(A);

    return 0;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/189088.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MATLAB在信号系统中的应用

1.产生一个幅度为1, 基频为2Hz&#xff0c;占空比为50%的周期方波.要求画出图形。 在MATLAB中&#xff0c;函数square(w0*t, DUTY)产生基本频率为w0 (周期T2*pi/w0)、占空比DUTY (τ/T)*100的周期矩形波&#xff08;方波&#xff09;&#xff0c;默认情况下占空比DUTY50。占空…

Nivision 图像处理方法-Brightness(BCGTransform)实现验证测试

测试发现NIvision中实际使用的公式是: int brightness199; float contrast61.38; float gamma0.52; uchar lut[256]; float k tan(contrast*CV_PI / 180); for (int i 0; i < 256; i) { lut[i] saturate_cast<uchar>(k*(pow(i, gamma)/ pow(255, gamma) * 2…

操作系统——操作系统概论s

一、操作系统基本概念 1 操作系统定义 操作系统是裸机上的第一层软件&#xff0c;它是对硬件系统功能的首次扩充&#xff0c; 用以填补人与机器之间的鸿沟。 OS定义&#xff1a;操作系统是控制和管理计算机系统内各种硬件和软件资源&#xff0c;有效地组织多道程序运行的系统软…

小程序中的大道理之四--单元测试

在讨论领域模型之前, 先继续说下关于测试方面的内容, 前面为了集中讨论相应主题而对此作了推迟, 下面先补上关于测试方面的. 测试覆盖(Coverage) 先回到之前的一些步骤上, 假设我们现在写好了 getPattern 方法, 而 getLineContent 还处于 TODO 状态, 如下: public String ge…

Python 前后端分离项目Vue部署应用

一、视图创建 from django.http import JsonResponse from django.shortcuts import render# Create your views here. from django.views import Viewclass IndexView(View):def get(self,request):# 前后端分离 &#xff08;前端JS代码渲染数据&#xff09;return JsonRespo…

html实现360度产品预览(附源码)

文章目录 1.设计来源1.1 拖动汽车产品旋转1.2 汽车产品自动控制 2.效果和源码2.1 动态效果2.2 源代码 源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/134613931 html实现360度产品预览&#xff08;附源码&…

【代码】平抑风电波动的电-氢混合储能容量优化配置(完美复现)matlab-yalmip-cplex/gurobi

程序名称&#xff1a;平抑风电波动的电-氢混合储能容量优化配置 实现平台&#xff1a;matlab-yalmip-cplex/gurobi 代码简介&#xff1a;针对电-氢混合系统协同平抑接入新型电力系统的 新能源波动问题&#xff0c;提出考虑碱性电解槽运行特性的电-氢 混合储能容量优化配置方案…

MSI Center,XBox从任务栏取消固定

1&#xff0c;设置查看方式中隐藏项目可见 2&#xff0c;进入文件夹&#xff1a;C:\Users\Default\AppData\Local\Microsoft\Windows\Shell 找到下面这两个文件夹&#xff1a; 3&#xff0c;修改文件名或者删除这两个文件即可

MySQL 批量插入记录报 Error 1390 (HY000)

文章目录 1.背景2.问题3.分批插入4.一次最多能插入多少条记录&#xff1f;5.什么是 Prepared Statement&#xff1f;参考文献 1.背景 Golang 后台服务使用 GORM 实现与 MySQL 的交互&#xff0c;在实现一个通过 Excel 导入数据的接口时&#xff0c;使用 Save 方法一次性插入大…

Mybatis-Plus 租户使用

Mybatis-Plus 租户使用 文章目录 Mybatis-Plus 租户使用一. 前言1.1 租户存在的意义1.2 租户框架 二. Mybatis-plus 租户2.1 租户处理器2.2 前置准备1. 依赖2. 表及数据准备3. 代码生成器 2.3 使用 三. 深入使用3.1 前言3.2 租户主体设值&#xff0c;取值3.3 部分表全量db操作3…

《斯坦福数据挖掘教程·第三版》读书笔记(英文版)Chapter 3 Finding Similar Items

来源&#xff1a;《斯坦福数据挖掘教程第三版》对应的公开英文书和PPT It is therefore a pleasant surprise to learn of a family of techniques called locality-sensitive hashing, or LSH, that allows us to focus on pairs that are likely to be similar, without hav…

第二十章 解读PASCAL VOC2012与MS COCO数据集(工具)

PASCAL VOC2012数据集 Pascal VOC2012官网地址&#xff1a;http://host.robots.ox.ac.uk/pascal/VOC/voc2012/ 官方发表关于介绍数据集的文章 《The PASCALVisual Object Classes Challenge: A Retrospective》&#xff1a;http://host.robots.ox.ac.uk/pascal/VOC/pubs/everi…

github上不去

想要网上找代码发现github上不去了 发现之前的fastgit也用不了了 搜了很多地方终于找到了 记录保存一下 fastgithub最新下载 选择第二个下载解压就行 使用成功&#xff01;

物联网AI MicroPython学习之语法 实时时钟RTC

学物联网&#xff0c;来万物简单IoT物联网&#xff01;&#xff01; RTC 介绍 模块功能: 实时时钟RTC驱动模块 接口说明 RTC - 构建RTC对象 函数原型&#xff1a;RTC()参数说明&#xff1a; 无 返回值&#xff1a; 构建的RTC对象。 datetime - RTC时钟操作 函数原型&a…

外包干了2个月,技术退步明显了...

先说一下自己的情况&#xff0c;大专生&#xff0c;19年通过校招进入湖南某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年8月份&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…

KVM虚拟机的NAT网络模式原理及过程展示

NAT的方式及原理 NAT方式是KVM安装后的默认方式。 它支持主机与虚拟机的互访&#xff0c;同时也支持虚拟机访问互联网&#xff0c;但不支持外界访问虚拟机。 default是宿主机安装虚拟机支持模块的时候自动安装的。 其中 virbr0是由宿主机虚拟机支持模块安装时产生的虚拟网络接…

Android设计模式--外观模式

弈之为术&#xff0c;在人自悟 一&#xff0c;定义 外观模式要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。提供一个高层次的接口&#xff0c;使得子系统更易于使用。 外观模式在开发中的使用频率是非常高的&#xff0c;尤其是在第三方的SDK里面&#xff0…

【网络】DNS协议、ICMP协议、NAT技术

DNS协议、ICMP协议、NAT技术 一、DNS协议1、产生背景2、域名简介3、域名解析的工作流程4、使用dig工具分析DNS过程 二、ICMP协议1、ICMP介绍2、ICMP协议格式3、ping命令4、traceroute命令 三、NAT技术1、NAT技术背景2、NAT IP转换过程3、地址转换表4、NAPT技术5、重新理解路由器…

阿里元境亮相第八届世界物联网大会,分享元计算对数字文旅的创新赋能

2023&#xff08;第八届&#xff09;世界物联网大会于11月20日在中国北京隆重开幕。联合国秘书长安东尼奥古特雷斯在开幕式发表书面致辞时特别提到&#xff1a;“在一个相互连接的世界&#xff0c;你们的主题‘新物联、新经济、新时代’是数字技术影响力的见证”。 11月21日上午…

K8s 中 Pod OOMKilled 原因

目录 Exit Code 137 解决方案 JVM 感知 cgroup 限制 使用 JDK9 的容器感知机制尝试 问题分析 容器内部感知 CGroup 资源限制 在 Java10 中&#xff0c;改进了容器集成 JVM 参数 MaxDirectMemorySize -XX:MaxDirectMemorySize 的默认值是什么&#xff1f; 其他获取 ma…