【数据结构】【王道】【树与二叉树】二叉树层序遍历实现(可直接运行)

该博客详细介绍了如何使用链式队列实现二叉树的层序遍历,即广度优先搜索。通过初始化队列,从根节点开始,逐层访问每个节点并将其左右孩子入队,直至队列为空。同时,提供了完整的C语言代码实现,包括树的插入、访问、深度计算等辅助函数。在文章末尾,展示了程序的运行结果。

总目录:https://blog.youkuaiyun.com/treesorshining/article/details/125726400

1.说明

层序遍历即是一层一层从左至右访问二叉树每个结点,类似于广度优先遍历。

实现思路:借助一个辅助队列,从根节点开始,根结点入队,访问此结点后出队,并将此结点的左右孩子入队(如果有),再依次对队头结点执行上述操作,直至队列为空为止。

2.算法实现

// 层序遍历
// 即一层一层从左至右访问每个结点,即广度优先遍历
// 此操作需要一个辅助队列,从根结点开始入队,访问此结点后出队,并将此结点的左右孩子入队(如果有)
// 再对每一个入队结点重复上述操作直至遍历完成(队列空)
void LevelOrder(BiTree T) {
    LinkQueue Q;
    // 初始化辅助队列
    InitQueue(Q);
    BiTree p;
    // 根节点入队
    EnQueue(Q, T);
    // 队列不空则一直循环
    while(!IsEmpty(Q)) {
        // 队头结点出队
        DeQueue(Q, p);
        // 访问出队结点
        visit(p);
        // 访问出队结点
        if(p->lchild != NULL) {
            // 左孩子入队
            EnQueue(Q, p->lchild);
        }
        if(p->rchild != NULL) {
            // 右孩子入队
            EnQueue(Q, p->rchild);
        }
        // 释放空间
        free(p);
    }
}

3.完整代码

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

typedef struct BiTNode {
    // 数据域
    char data;
    // 左、右孩子指针
    struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;

typedef struct LinkNode {   // 链式队列结点
    // 此处存的是指针而不是结点,可节省大量空间
    BiTNode* data;   // 数据域
    struct LinkNode *next;  // 指针域
} LinkNode;

typedef struct {    // 链式队列
    // 如果不设置尾指针,若要插入,遍历到队尾再插入,时间复杂度O(n)
    LinkNode *front, *rear; // 队列的队头和队尾指针
} LinkQueue;

// 初始化
void InitTree(BiTree &T) {
    // 初始化可将根节点置空,空树
    T = NULL;
    // 插入根节点
    // 分配空间
    T = (BiTree)malloc(sizeof(BiTree));
    // 赋值
    T->data = 'A';
    // 初始无左右子树
    T->lchild = NULL;
    T->rchild = NULL;
}

// 左插入结点
bool InsertLeftTreeNode(BiTNode* &T, char x) {
    // 分配空间
    BiTNode *p = (BiTNode*)malloc(sizeof(BiTNode));
    // 分配空间失败的情况
    if(p == NULL) {
        return false;
    }
    // 数据域赋值
    p->data = x;
    // 初始插入,无左右孩子,置空
    p->lchild = NULL;
    p->rchild = NULL;
    // 作为指定插入结点的左孩子
    T->lchild = p;
    return true;
}

// 右插入结点
bool InsertRightTreeNode(BiTNode* &T, char x) {
    // 分配空间
    BiTNode *p = (BiTNode*)malloc(sizeof(BiTNode));
    // 分配空间失败的情况
    if(p == NULL) {
        return false;
    }
    // 数据域赋值
    p->data = x;
    // 初始插入,无左右孩子,置空
    p->lchild = NULL;
    p->rchild = NULL;
    // 作为指定插入结点的左孩子
    T->rchild = p;
    return true;
}

// 访问结点
void visit(BiTree T) {
    printf("%c   ", T->data);
}

// 树的深度
int treeDepth(BiTree T) {
    // 根结点为空,则深度为0
    if(T == NULL) {
        return 0;
    } else {
        // 递归遍历左子树,获得左子树深度
        int l = treeDepth(T->lchild);
        // 递归遍历右子树,获得右子树深度
        int r = treeDepth(T->rchild);
        // 树的深度=Max{左子树深度,右子树深度} + 1
        // 加1相当于访问根节点,包括根结点深度+1
        return l > r ? l + 1 : r + 1;
    }
}

// 初始化(带头结点)
void InitQueue(LinkQueue &Q) {
    // 初始时为头结点分配空间,并令头指针、尾指针都指向头结点
    Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));
    // 将头结点指针域置空
    Q.front->next = NULL;
}

// 判断队列是否为空
bool IsEmpty(LinkQueue Q) {
    // 头指针与尾指针指向同一地址(头结点即表示队列为空)
    // 或者也可以根据Q.front->next = NULL来进行判定
    if(Q.front == Q.rear) {
        return true;
    } else {
        return false;
    }
}

// 入队
bool EnQueue(LinkQueue &Q, BiTNode *x) {
    // 申请分配空间
    LinkNode *s = (LinkNode*)malloc(sizeof(LinkNode));
    // 内存分配失败的情况
    if(s == NULL) {
        return false;
    }
    // 将数据赋值给数据域
    s->data = x;
    // 由于队列必定在队尾插入,所以指针域要设为NULL
    s->next = NULL;
    // 入队操作
    Q.rear->next = s;
    // 修改队尾指针
    Q.rear = s;
    return true;
}

// 出队操作
bool DeQueue(LinkQueue &Q, BiTNode* &x) {
    // 空队的情况
    if(Q.front == Q.rear) {
        return false;
    }
    // 由于队列出队操作一定是在队头进行,所以以一临时指针指向队头结点(非头结点,是队列第一个结点)
    LinkNode *p = Q.front->next;
    // 将队头元素赋值给x
    x = p->data;
    // 令队头指针指向队头元素下一个元素
    Q.front->next = p->next;
    // 出队为最后一个结点的情况
    if(Q.rear == p) {
        // 修改尾指针,使其指向头结点,以免之后释放空间时尾指针指向未知地点
        // 同时,也表示此队列已是空队列
        Q.rear = Q.front;
    }
    // 释放空间
    // 由于之后还需要取分支节点的左右孩子,所以不能在此处释放空间
    // free(p);
    return true;
}

// 层序遍历
// 即一层一层从左至右访问每个结点,即广度优先遍历
// 此操作需要一个辅助队列,从根结点开始入队,访问此结点后出队,并将此结点的左右孩子入队(如果有)
// 再对每一个入队结点重复上述操作直至遍历完成(队列空)
void LevelOrder(BiTree T) {
    LinkQueue Q;
    // 初始化辅助队列
    InitQueue(Q);
    BiTree p;
    // 根节点入队
    EnQueue(Q, T);
    // 队列不空则一直循环
    while(!IsEmpty(Q)) {
        // 队头结点出队
        DeQueue(Q, p);
        // 访问出队结点
        visit(p);
        // 访问出队结点
        if(p->lchild != NULL) {
            // 左孩子入队
            EnQueue(Q, p->lchild);
        }
        if(p->rchild != NULL) {
            // 右孩子入队
            EnQueue(Q, p->rchild);
        }
        // 释放空间
        free(p);
    }
}

int main() {
    BiTree T;
    InitTree(T);
    InsertLeftTreeNode(T, 'B');
    InsertRightTreeNode(T, 'C');
    InsertLeftTreeNode(T->lchild, 'D');
    InsertRightTreeNode(T->lchild, 'E');
    InsertLeftTreeNode(T->rchild, 'F');
    InsertRightTreeNode(T->rchild, 'G');
    printf("\ntreeDepth:%d\n", treeDepth(T));
    printf("LevelOrder\n");
    LevelOrder(T);
}

4.运行结果

在这里插入图片描述

### C语言中二叉树层序遍历的教学资源代码示例 #### 关于王道督学营中的二叉树层序遍历教学内容 在王道C语言督学营的数据结构课程中,对于二叉树的操作讲解非常详尽,其中包括了二叉树的创建、前序遍历、中序遍历、后序遍历以及层序遍历等内容[^1]。 #### 二叉树层序遍历的概念 层序遍历是指按照层次从上到下逐层访问节点的过程。每一层都从左向右依次访问各个结点,在同一层内按从左至右顺序处理各结点的孩子结点。为了实现这一过程,通常会借助队列这种数据结构来辅助完成操作[^3]。 #### 实现二叉树层序遍历的代码示例 下面是一个简单的C语言程序,展示了如何通过队列来进行二叉树层序遍历: ```c #include <stdio.h> #include <stdlib.h> // 定义二叉树节点结构体 typedef struct TreeNode { int val; struct TreeNode *left, *right; } TreeNode; // 创建新节点 TreeNode* createNode(int value) { TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode)); newNode->val = value; newNode->left = NULL; newNode->right = NULL; return newNode; } // 队列定义及其基本功能 #define MAX_SIZE 100 int front = -1, rear = -1; TreeNode* queue[MAX_SIZE]; void enqueue(TreeNode* node) { if ((rear + 1) % MAX_SIZE == front) { // 判断队满 printf("Queue is full.\n"); exit(1); } if (front == -1 && rear == -1) { // 初始化队列 front = 0; rear = 0; } else { rear = (rear + 1) % MAX_SIZE; // 循环队列入队 } queue[rear] = node; } TreeNode* dequeue() { if (front == -1 || front > rear) { // 判断队空 printf("Queue is empty.\n"); exit(1); } TreeNode* temp = queue[front]; if (front == rear) { // 如果只剩下一个元素,则重置队列状态 front = -1; rear = -1; } else { front = (front + 1) % MAX_SIZE; // 出队 } return temp; } // 执行层序遍历并打印结果 void levelOrderTraversal(TreeNode* root) { if (!root) return; enqueue(root); // 将根节点加入队列 while (front != -1 && front <= rear) { TreeNode* currentNode = dequeue(); printf("%d ", currentNode->val); if (currentNode->left) enqueue(currentNode->left); if (currentNode->right) enqueue(currentNode->right); } } ``` 此段代码实现了基于循环队列的二叉树层序遍历算法,并提供了相应的测试案例以验证其正确性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Silver Star

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值