• 【数据结构】二叉树的层序遍历(四)


     目录

    一,层序遍历概念

    二,层序遍历的实现

            1,层序遍历的实现思路

            2,创建队列

            Queue.h

            Queue.c

            3,创建二叉树

            BTree.h

            BTree.c

            4,层序遍历的实现


    一,层序遍历概念

    层序遍历:除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历;

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

    二,层序遍历的实现

            1,层序遍历的实现思路

    层序遍历:按照每一行从左到右对二叉树的各个结点进行访问

    但是呢,对一层访问结束了该如何访问下一层呢?就拿上图举例,访问完(4)结点后该如何访问(3)结点呢?(4)结点中并没有(3)结点的信息;

    算法思路:

    可以借助一个队列,首先将二叉树的根结点入队,然后访问出队结点并出队,如果有左孩子结点,左孩子结点也入队;如果有右孩子结点,右孩子结点也入队。然后访问出队结点并出队,直到队列为空为止

    过程演示: 

    (1)入队列,访问队头结点(1),然后(1)出队列,此时(1)的左子树(2)右子树(4)相继入队列;此时队列: 头<---- (2)(4)    <---尾

    访问队头结点(2),然后(2)出队列,此时(2)的左子树(3)入队列,此时队列:(4)(3)

    访问队头结点(4),然后(4)出队列,此时(4)的左子树(5)右子树(6)相继入队列;

    此时队列:(3)(5)(6)

    访问队头结点(3),然后(3)出队列,因为(3)没有左右子树,此时没有数据入队列,此时队列:(5)(6)

    访问头结点(5),然后(5)出队列,此时队列:(6)

    访问头结点(6),然后(6)出队列,此时队列:NULL,结束!

    下面是另一棵二叉树的遍历来帮助我们理解;

            2,创建队列

    首先我们得创建一个队列,队列具体细节就不过多解释了,之前博客有专门的详细介绍过;

    队列的性质:先进先出,也就是尾插,头删的单链表;

            Queue.h

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #pragma once
    3. #include
    4. #include
    5. #include
    6. #include"BTree.h"
    7. typedef BTNode* QDataType;
    8. //结点
    9. typedef struct QListNode
    10. {
    11. struct QListNode* next;
    12. QDataType data;
    13. }QNode;
    14. // 队列
    15. typedef struct Queue
    16. {
    17. QNode* front; // 队头
    18. QNode* rear; //队尾
    19. int size;
    20. }Queue;
    21. // 初始化队列
    22. void QueueInit(Queue* q);
    23. // 队头入队列
    24. void QueuePush(Queue* q, QDataType data);
    25. // 队尾出队列
    26. void QueuePop(Queue* q);
    27. // 获取队列头部元素
    28. QDataType QueueFront(Queue* q);
    29. // 获取队列队尾元素
    30. QDataType QueueBack(Queue* q);
    31. // 获取队列中有效元素个数
    32. int QueueSize(Queue* q);
    33. // 判空
    34. int QueueEmpty(Queue* q);
    35. // 销毁队列
    36. void QueueDestroy(Queue* q);

            Queue.c

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #define _CRT_SECURE_NO_WARNINGS 1
    3. #include"Queue.h"
    4. // 初始化队列
    5. void QueueInit(Queue* q)
    6. {
    7. assert(q);
    8. q->front = q->rear = NULL;
    9. q->size = 0;
    10. }
    11. // 队尾入队列
    12. void QueuePush(Queue* q, QDataType data)
    13. {
    14. assert(q);
    15. QNode* newnode = (QNode*)malloc(sizeof(QNode));
    16. if (newnode == NULL)
    17. {
    18. perror("malloc");
    19. exit(-1);
    20. }
    21. newnode->next = NULL;
    22. newnode->data = data;
    23. if (q->front /*= q->rear*/ == NULL)//谨记判断不要用此等格式
    24. {
    25. q->front = q->rear = newnode;
    26. }
    27. else
    28. {
    29. q->rear->next = newnode;
    30. q->rear = newnode;
    31. }
    32. q->size++;
    33. }
    34. // 队头出队列
    35. void QueuePop(Queue* q)
    36. {
    37. assert(q);
    38. assert(!QueueEmpty(q));
    39. if (q->front->next == NULL)
    40. {
    41. free(q->front);
    42. q->front = q->rear = NULL;
    43. }
    44. else
    45. {
    46. QNode* next = q->front->next;
    47. free(q->front);
    48. q->front = next;
    49. }
    50. q->size--;
    51. }
    52. // 获取队列头部元素
    53. QDataType QueueFront(Queue* q)
    54. {
    55. assert(q);
    56. assert(!QueueEmpty(q));
    57. return q->front->data;
    58. }
    59. // 获取队列队尾元素
    60. QDataType QueueBack(Queue* q)
    61. {
    62. assert(q);
    63. assert(!QueueEmpty(q));
    64. return q->rear->data;
    65. }
    66. // 获取队列中有效元素个数
    67. int QueueSize(Queue* q)
    68. {
    69. assert(q);
    70. return q->size;
    71. }
    72. // 检测队列是否为空,如果为空返回非零结果,如果非空返回0
    73. int QueueEmpty(Queue* q)
    74. {
    75. assert(q);
    76. return q->size == 0;
    77. }
    78. // 销毁队列
    79. void QueueDestroy(Queue* q)
    80. {
    81. assert(q);
    82. QNode* cur = q->front;
    83. QNode* next = NULL;
    84. while (cur)
    85. {
    86. next = cur->next;
    87. free(cur);
    88. cur = next;
    89. }
    90. cur = NULL;
    91. q->rear = NULL;
    92. }

    这队列已经构造完成了,我们还需要一棵二叉树;

            3,创建二叉树

    二叉树之前我们也创建过,现在也不过多介绍了,直接上硬菜!

            BTree.h

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. typedef int BTDataType;
    6. //二叉链
    7. typedef struct BinaryTreeNode
    8. {
    9. BTDataType data; // 当前结点值域
    10. struct BinaryTreeNode* left; // 指向当前节点左孩子
    11. struct BinaryTreeNode* right; // 指向当前节点右孩子
    12. }BTNode;
    13. //动态创立新结点
    14. BTNode* BuyNode(BTDataType x);
    15. //创建二叉树
    16. BTNode* GreatBTree();

            BTree.c

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include"BTree.h"
    3. #include"Queue.h"
    4. //动态创立新结点
    5. BTNode* BuyNode(BTDataType x)
    6. {
    7. BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
    8. assert(newnode);
    9. newnode->data = x;
    10. newnode->left = NULL;
    11. newnode->right = NULL;
    12. return newnode;
    13. }
    14. //创建二叉树
    15. BTNode* GreatBTree()
    16. {
    17. BTNode* node1 = BuyNode(1);
    18. BTNode* node2 = BuyNode(2);
    19. BTNode* node3 = BuyNode(3);
    20. BTNode* node4 = BuyNode(4);
    21. BTNode* node5 = BuyNode(5);
    22. BTNode* node6 = BuyNode(6);
    23. node1->left = node2;
    24. node1->right = node4;
    25. node2->left = node3;
    26. node4->left = node5;
    27. node4->right = node6;
    28. return node1;
    29. }

    这个队列和二叉树的 .c文件都要包含彼此的头文件,将他们链接起来;

            4,层序遍历的实现

    按照之前的分析思路,以此构建代码;

    1. //层序遍历
    2. void LevelOrder(BTNode* root)
    3. {
    4. Queue q;
    5. // 初始化队列
    6. QueueInit(&q);
    7. // 队尾入队列
    8. if (root)
    9. {
    10. QueuePush(&q, root);
    11. }
    12. while (!QueueEmpty(&q))
    13. {
    14. printf("%d ", QueueFront(&q)->data);
    15. BTNode* cur = QueueFront(&q);
    16. // 队头出队列
    17. QueuePop(&q);
    18. if (cur->left)
    19. {
    20. QueuePush(&q, cur->left);
    21. }
    22. if (cur->right)
    23. {
    24. QueuePush(&q, cur->right);
    25. }
    26. }
    27. }
    1. int main()
    2. {
    3. BTNode* root = GreatBTree();
    4. //层序遍历
    5. LevelOrder(root);
    6. return 0;
    7. }

     确实是一层一层进行遍历的;

    之前的遍历都是递归实习的,而层序遍历是循环实现的,目前用c语言来实现的话因为没有队列的库,实现起来特别的繁琐,不过好理解,本身并不难,这就是层序遍历的实现;

    第四阶段带大家了实现了层序遍历,后序会带大家刷一会经典题目来进行巩固;

    后面博主会陆续更新;

    如有不足之处欢迎来补充交流!

    完结。


  • 相关阅读:
    图文手把手教程--ESP32 一键配网(Smartconfig、Airkiss)
    自己写过比较蠢的代码:从失败中学习的经验
    Docker没有vim如何安装,apt-get update报ERR404解决方案
    初见 monorepo
    [数据集][VOC]高质量的目标检测数据集合集(持续更新)
    TCP协议的相关特性
    编写虚拟UART驱动程序-框架
    滑动窗口练习(一)— 固定窗口最大值问题
    numpy教程:Array-Oriented Programming with Arrays 数组导向编程
    基于Python实现的换脸软件
  • 原文地址:https://blog.csdn.net/m0_71676870/article/details/132921191