【每天学习一点算法 2025/12/19】二叉树的层序遍历

每天学习一点算法 2025/12/19

题目:二叉树的层序遍历

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

输入:root = [3,9,20,null,null,15,7]

输出:[[3],[9,20],[15,7]]

emmmmmmmm,层序遍历就是前几个二叉树相关问题里面的迭代法,这题目顺序对吗?

OK,层序遍历主要就是利用队列存储节点,然后循环队列的过程中将子节点入队列从而实现逐层拓展遍历二叉树。

function levelOrder(root: TreeNode | null): number[][] {
  if (!root) return []
  const result: number[][] = [] // 用于存储遍历结果
  const queue: Array<TreeNode | null> = [] // 队列用于遍历树节点
  queue.push(root) // 初始根节点入队列
  
  // 循环遍历
  while (queue.length > 0) {
    const len = queue.length // 暂存当前层的节点数
    const level = [] // 用于存储当前层节点值
    // 循环当前层节点,存储节点值,并拓展下一层节点
    for (let i = 0; i < len; i++) {
      const node = queue.shift()!
      level.push(node.val)
      node.left && queue.push(node.left)
      node.right && queue.push(node.right)
    }
    result.push(level)
  }
  return result
}

题目来源:力扣(LeetCode)

1.问题描述 设有二叉树如图1.7.1所示: 图1.7.1 二叉树 编程实现有关二叉树的下列运算: (1)创建一棵二叉树; (2)采用递归方法分别实现对上述二叉树的先序遍历、中序遍历、后序遍历,输出遍历序列; (3)采用链栈的迭代方法分别实现对上述二叉树的先序遍历、中序遍历、后序遍历,输出遍历序列; (4)利用队列实现二叉树层序遍历。 2.基本要求 (1)分别设计二叉树、链栈结点、链队列结点的数据结构; (2)在参考程序中的下划线处填入适当的语句,完善参考程序; (3)理解并掌握二叉树的各种遍历算法; (4)上机调试、测试参考程序,打印测试结果,对结果进行分析。 3.数据结构设计 (1)二叉树结点数据结构 typedef struct BiTNode { // 定义树结束结构 char data; // 假定树的元素类型为int struct BiTNode *lchild; // 左子树 struct BiTNode *rchild; // 右子树 } BiTNode,*BiTree; (2)链栈结点数据结构(用于二叉树非递归迭代遍历) typedef struct Stack{ // 定义链栈结点结构 BiTNode *t; // 栈结点元素为指向二叉树结点的指针 int flag; // 后序遍历时用到该标志 struct Stack *next; // 栈结点链指针 } Stack, *LinkStack; (3)链队列数据结构(用于二叉树层序遍历) typedef struct QNode{ // 定义链队列结点结构 BiTree t; // 链队列结点数据域 struct QNode *next; // 链队列结点指针域 }QNode, *QueuePtr; typedef struct { // 队列类型 QueuePtr front; // 队首指针 QueuePtr rear; // 队尾指针 }LinkQueue; 4.算法设计 (1)二叉树的遍历、链栈的基本操作、链队列的基本操作算法设计 // ① 进栈函数 void Push(LinkStack &top, BiTree tree) { // 树结点入栈 LinkStack p; // 工作指针 p=(Stack *)malloc(sizeof(Stack)); // 申请栈结点 p->t = tree; // 根结点进栈 p->next = top; // 新栈结点指向栈顶 top = p; // 栈顶为新结点 } // ② 出栈函数 void Pop(LinkStack &top, BiTree &tree) // 出栈,栈内元素赋值给树结点 { LinkStack p=top; // 工作指针 if(top == NULL) // 空栈 tree = NULL; else { // 栈非空 tree=top->t; // 栈顶结点元素赋值给树结点 top = top->next; // 栈顶指向下一个链接,完成出栈 free(p); // 释放栈顶结点空间 } } // ③ 初始化链队列函数 Status InitQueue(LinkQueue &Q) { // 创建一个带附加表头结点的空链队列Q Q.front= Q.rear = (QueuePtr)malloc(sizeof(QNode)); if(!Q.front) return ERROR; Q.front->next = NULL; return OK; } // ④ 进队函数 Status EnQueue(LinkQueue &Q, BiTree e) { //将元素e插入到带头结点的链队列Q中 QueuePtr p; p=(QueuePtr)malloc(sizeof(QNode)); if(!p) return ERROR; p->t = e; p->next=NULL; Q.rear->next = p; Q.rear=p; return OK; } // ⑤ 出队函数 Status DeQueue(LinkQueue &Q, BiTree &e) { //若队列不空,则队首元素出队列,用e返回其值,返回OK,否则返回ERROR QueuePtr p; if(Q.rear==Q.front) return ERROR; p=Q.front->next; e=p->t; Q.front->next=p->next; if(Q.rear==p) Q.rear=Q.front; free(p); return OK; } // ⑥先序遍历,递归方法 void re_PreOrder(BiTNode *tree) { if(tree!=NULL) { // 不为空子树时递归遍历 printf("%c ",tree->data); // 访问根结点 re_PreOrder (tree->lchild); // 先序遍历左子树 re_PreOrder (tree->rchild); // 先序遍历右子树 } } // ⑦中序遍历,递归方法 void re_MidOrder(BiTNode *tree) { // 请编写中序遍历子程序 1 } // ⑧后序遍历,递归方法 void re_PostOrder(BiTNode *tree) { if(tree!=NULL) { // 不为空子树时递归遍历 re_PostOrder (tree->lchild); // 先后序遍历左子树 re_PostOrder (tree->rchild); // 再后序遍历右子树 printf("%c ",tree->data); // 最后访问根结点 } } // ⑨先序遍历,采用链栈的迭代方法 void st_PreOrder(BiTNode *tree) { LinkStack top; // 栈顶指针 top=NULL; // 初始化为空栈 while(tree!=NULL) { // 二叉树还未遍历完 2 ; // 访问根结点 if( 3 ) // 右子树结点入栈 Push(top, tree->rchild); if(tree->lchild!=NULL) // 左子树结点入栈 4 ; Pop(top, tree); // 树结点出栈 } } // ⑩中序遍历,采用链栈的迭代方法 void st_MidOrder(BiTNode *tree) { LinkStack top; // 栈顶指针 top = NULL; // 初始化为空栈 while( 5 ){ // 循环条件为二叉树还未遍历完,或栈非空 while(tree!=NULL) { // 二叉树还未遍历完 Push(top, tree); // 树结点入栈 6 ; // 沿左子树前进,将经过的结点依次进栈 } if(top!=NULL){ // 左子树点入栈结束,且栈非空 Pop(top, tree); // 树结点出栈 7 ; // 访问根结点 8 ; // 向右子树前进 } } } // ○11后序遍历,采用链接栈的送代方法 void st_PostOrder(BiTNode *tree) { LinkStack top; // 栈顶指针 top=NULL; // 初始化为空栈 do { while( 9 ) { // 二叉树还未历完 Push(top, tree); // 树结点人栈 top->flag = 0; // 标志为0,表示右子树未访问。 10 ; // 沿左子树前进,将经过的结点依次进栈 } if(top!=NULL) { // 栈非空 while(top!=NULL&& 11 ){ // 右子树已访问 Pop(top, tree); // 出栈 printf("%c ", tree->data); } if(top!=NULL) { 12 ; // 置右子树为访问标志 tree = (top->t)->rchild; // 查找栈顶无素的右子树 } } } while(top!=NULL); // 循环条件为栈非空 } // ○12二叉树层序遍历 void LevelOrder(BiTNode *root) { LinkQueue Q; BiTree p; if (root !=NULL) { InitQueue(Q); EnQueue(Q,root); while( 13 ) { // 循环条件为队非空 DeQueue(Q,p); printf("%c ", p->data); if(p->lchild!=NULL) EnQueue(Q, p->lchild); if(p->rchild!=NULL) EnQueue(Q, p->rchild); } //While printf("\n"); } //if } //LevelOrder // ○13创建二叉树 void CreateBiTree(BiTree &T) { // 先序递归遍历方式创建一棵二叉树 char ch; scanf("\n%c",&ch); // 输入根结点的值 if (ch =='#') // 终止项 T = NULL; else { T = (BiTree)malloc(sizeof(BiTNode)); // 创建根结点 if (!T) exit(-1); T->data = ch; printf("\n请输入%c结点的左子结点(#表无):",T->data ); // 先序遍历创建左子树 CreateBiTree(T->lchild); printf("\n请输入%c结点的右子结点(#表无):",T->data ); // 先序遍历创建右子树 CreateBiTree(T->rchild); } } //○14以括号表示格式输出二叉树 void OutputBiTree(BiTree T) { // 先序递归遍历方式输出括号表示的二叉树 if(T!=NULL) // 终止项 { printf("%c", T->data); // 访问根结点 if(T->lchild!=NULL||T->rchild!=NULL) { printf("("); // 根的孩子用圆括号对括 OutputBiTree(T->lchild); // 先序遍历输出左子树 if(T->rchild!=NULL) printf(","); // 根的左右孩子以“,”分隔 OutputBiTree(T->rchild); // 先序遍历输出右子树 printf(")"); // 根的孩子用圆括号对括 } } } (2).主函数。 // 本程序实现了二叉查找树的先序遍历,中序遍历,后序遍历的递归和迭代方法。 void main() { BiTNode *proot; // 定义树 proot=NULL; // 初始化为空树 printf("请输入根结点元素(#表无):"); 14 ; // 创建二叉树 printf("\n(1)二叉树创建成功,其括号表示格式输出:\n\t"); OutputBiTree(proot); printf("\n(2)先序遍历,递归方法\n\t"); 15 ; // 先序遍历,递归方法 printf("(3)中序遍历,递归方法\n\t"); 16 ; // 中序遍历,递归方法 printf("(4)后序遍历,递归方法\n\t"); 17 ; // 后序遍历,递归方法 printf("(5)先序遍历,链接栈的迭代方法\n\t"); 18 ; // 先序遍历,采用链接栈的迭代方法 printf("(6)中序遍历,链接栈的迭代方法\n\t"); 19 ; // 中序遍历,采用链接栈的迭代方法 printf("(7)后序遍历,链接栈的迭代方法\n\t"); 20 ; // 后序遍历,采用链接栈的迭代方法 printf("(8)层序遍历,链队列的迭代方法\n\t"); LevelOrder( proot ); // 后序遍历,采用链接栈的迭代方法 }
11-14
### 完善二叉树中序遍历递归方法 中序遍历的顺序是左子树 -> 根节点 -> 右子树。以下是完善后的中序遍历递归方法: ```c #include <stdio.h> // 定义二叉树节点结构 typedef struct BiTNode { char data; struct BiTNode *lchild, *rchild; } BiTNode, *BiTree; // 中序遍历 -- 递归 void InOrder(BiTree T) { if (T != NULL) { InOrder(T->lchild); printf("%c ", T->data); InOrder(T->rchild); } } ``` ### 补充二叉树先序、中序、后序遍历迭代方法 #### 先序遍历迭代方法 先序遍历的顺序是根节点 -> 左子树 -> 右子树。 ```c #include <stdio.h> #include <stdlib.h> // 定义二叉树节点结构 typedef struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; } TreeNode; // 先序遍历 -- 迭代 #include <stdio.h> #include <stdlib.h> // 定义二叉树节点结构 typedef struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; } TreeNode; // 先序遍历 -- 迭代 void preorderTraversal(TreeNode* root) { if (root == NULL) return; TreeNode* stack[100]; int top = 0; stack[top++] = root; while (top > 0) { TreeNode* node = stack[--top]; printf("%d ", node->val); if (node->right != NULL) stack[top++] = node->right; if (node->left != NULL) stack[top++] = node->left; } } ``` #### 中序遍历迭代方法 ```c #include <stdio.h> #include <stdlib.h> // 定义二叉树节点结构 typedef struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; } TreeNode; // 中序遍历 -- 迭代 void inorderTraversal(TreeNode* root) { TreeNode* stack[100]; int top = 0; TreeNode* cur = root; while (cur != NULL || top > 0) { if (cur != NULL) { stack[top++] = cur; cur = cur->left; } else { cur = stack[--top]; printf("%d ", cur->val); cur = cur->right; } } } ``` #### 后序遍历迭代方法 ```c #include <stdio.h> #include <stdlib.h> // 定义二叉树节点结构 typedef struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; } TreeNode; // 后序遍历 -- 迭代 void postorderTraversal(TreeNode* root) { if (root == NULL) return; TreeNode* stack[100]; int top = 0; TreeNode* prev = NULL; TreeNode* cur = root; while (cur != NULL || top > 0) { while (cur != NULL) { stack[top++] = cur; cur = cur->left; } cur = stack[--top]; if (cur->right == NULL || cur->right == prev) { printf("%d ", cur->val); prev = cur; cur = NULL; } else { stack[top++] = cur; cur = cur->right; } } } ``` ### 主函数及测试 ```c #include <stdio.h> #include <stdlib.h> // 定义二叉树节点结构 typedef struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; } TreeNode; // 创建新节点 TreeNode* newNode(int val) { TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode)); node->val = val; node->left = NULL; node->right = NULL; return node; } // 先序遍历 -- 迭代 void preorderTraversal(TreeNode* root) { if (root == NULL) return; TreeNode* stack[100]; int top = 0; stack[top++] = root; while (top > 0) { TreeNode* node = stack[--top]; printf("%d ", node->val); if (node->right != NULL) stack[top++] = node->right; if (node->left != NULL) stack[top++] = node->left; } } // 中序遍历 -- 迭代 void inorderTraversal(TreeNode* root) { TreeNode* stack[100]; int top = 0; TreeNode* cur = root; while (cur != NULL || top > 0) { if (cur != NULL) { stack[top++] = cur; cur = cur->left; } else { cur = stack[--top]; printf("%d ", cur->val); cur = cur->right; } } } // 后序遍历 -- 迭代 void postorderTraversal(TreeNode* root) { if (root == NULL) return; TreeNode* stack[100]; int top = 0; TreeNode* prev = NULL; TreeNode* cur = root; while (cur != NULL || top > 0) { while (cur != NULL) { stack[top++] = cur; cur = cur->left; } cur = stack[--top]; if (cur->right == NULL || cur->right == prev) { printf("%d ", cur->val); prev = cur; cur = NULL; } else { stack[top++] = cur; cur = cur->right; } } } int main() { // 构建一个简单的二叉树 TreeNode* root = newNode(1); root->left = newNode(2); root->right = newNode(3); root->left->left = newNode(4); root->left->right = newNode(5); printf("Preorder Traversal: "); preorderTraversal(root); printf("\n"); printf("Inorder Traversal: "); inorderTraversal(root); printf("\n"); printf("Postorder Traversal: "); postorderTraversal(root); printf("\n"); return 0; } ``` ### 设计相关数据结构 #### 二叉树节点结构 ```c typedef struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; } TreeNode; ``` #### 链栈结点结构 ```c typedef struct StackNode { TreeNode* data; struct StackNode* next; } StackNode; typedef struct { StackNode* top; } LinkStack; ``` #### 链队列结点结构 ```c typedef struct QNode { TreeNode* data; struct QNode* next; } QNode; typedef struct { QNode* front; QNode* rear; } LinkQueue; ``` ### 调试测试及结果分析 将上述代码保存为 `.c` 文件,使用 C 编译器(如 GCC)进行编译和运行。通过构建一个简单的二叉树,分别调用先序、中序、后序遍历的迭代方法,输出遍历结果。根据遍历结果可以验证算法的正确性。不同的遍历顺序会输出不同的节点序列,先序遍历是根 -> 左 -> 右,中序遍历是左 -> 根 -> 右,后序遍历是左 -> 右 -> 根。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值