二叉树的层序遍历与完全二叉树判断

引言

在数据结构的世界里,二叉树是一种非常重要且基础的树形结构。它在很多领域都有广泛的应用,比如数据库索引、文件系统等。在处理二叉树时,我们常常需要对其进行遍历操作,而层序遍历就是其中一种重要的遍历方式。同时,判断一棵二叉树是否为完全二叉树也是一个常见的问题。本文将结合提供的代码,详细介绍二叉树的层序遍历和完全二叉树的判断方法。

代码背景

我们有几个相关的文件,BTree.h 和 BTree.cpp 定义和实现了二叉树的各种操作,Queue.h 和 Queue.cpp 实现了队列的基本操作,Test.cpp 是一个测试文件,用于验证这些操作的正确性。

队列的实现

在进行层序遍历和判断完全二叉树时,我们需要使用队列这种数据结构。队列的特点是先进先出(FIFO),非常适合用于层序遍历。下面是队列的主要操作代码(当然二叉树只需用到其中小部分队列操作):

// Queue.h
#pragma once

#include 
#include 
#include 
#include 

//这里须注意不可使用二叉树typedef的BTNode* 可能会因为无法找到产生大量报错
typedef struct BinaryTreeNode* QDataType;

typedef struct QueueNode
{
    struct QueueNode* next;
    QDataType val;
}QNode;

typedef struct Queue
{
    QNode* phead;
    QNode* ptail;
    int size;
}Queue;

//初始化与销毁队列
void QueueInit(Queue* pq);
void QueueDestory(Queue* pq);

//队尾插入
void QueuePush(Queue* pq, QDataType x);
//队头删除
void QueuePop(Queue* pq);

//取队头和队尾的数据
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);

//队列大小
int QueueSize(Queue* pq);

//判空
bool QueueEmpty(Queue* pq);
// Queue.cpp
#include "Queue.h"

//初始化与销毁队列
void QueueInit(Queue* pq)
{
    assert(pq);
    pq->phead = NULL;
    pq->ptail = NULL;
    pq->size = 0;
}

void QueueDestory(Queue* pq)
{
    assert(pq);
    QNode* cur = pq->phead;
    while(cur)
    {
        QNode* next = cur->next;
        free(cur);
        cur = next;
    }
    pq->phead = pq->ptail = NULL;
    pq->size = 0;
}

//队尾插入
void QueuePush(Queue* pq, QDataType x)
{
    assert(pq);
    QNode* newnode = (QNode*)malloc(sizeof(QNode));
    if(newnode == NULL)
    {
        perror("malloc fail!");
        return;
    }
    newnode->next = NULL;
    newnode->val = x;

    if(pq->ptail == NULL)
    {
        pq->phead = pq->ptail = newnode;
    }
    else
    {
        pq->ptail->next = newnode;
        pq->ptail = newnode;
    }
    pq->size++;
}

//队头删除
void QueuePop(Queue* pq)
{
    assert(pq);
    assert(pq->size != 0);

    //一个节点
    if(pq->phead->next == NULL)
    {
        free(pq->phead);
        pq->phead = pq->ptail = NULL;
    }
    else//多个节点
    {
        QNode* next =  pq->phead->next;
        free(pq->phead);
        pq->phead = next;
    }
    pq->size--;
}

//取队头和队尾的数据
QDataType QueueFront(Queue* pq)
{
    assert(pq);
    assert(pq->phead);
    return pq->phead->val;
}

QDataType QueueBack(Queue* pq)
{
    assert(pq);
    assert(pq->ptail);
    return pq->ptail->val;
}

//队列大小
int QueueSize(Queue* pq)
{
    assert(pq);
    return pq->size;
}

//判空
bool QueueEmpty(Queue* pq)
{
    assert(pq);
    return pq->size == 0;
}

二叉树的层序遍历

层序遍历是按照二叉树的层次从上到下、从左到右依次访问每个节点。我们可以使用队列来实现层序遍历。具体步骤如下:

  1. 初始化一个队列。
  2. 将根节点入队。
  3. 当队列不为空时,取出队头节点并访问它,然后将它的左右子节点(如果存在)入队。
  4. 重复步骤 3 直到队列为空。

以下是层序遍历的代码实现:

// BTree.cpp
// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
    Queue q;
    QueueInit(&q);
    if(root)
    {
        QueuePush(&q, root);
    }
    while(!QueueEmpty(&q))
    {
        BTNode* front = QueueFront(&q);
        QueuePop(&q);
        printf("%d ",front->data);
        if(front->left)
        {
            QueuePush(&q, front->left);
        }
        if(front->right)
        {
            QueuePush(&q, front->right);
        }
    }
    QueueDestory(&q);
}

判断二叉树是否为完全二叉树

完全二叉树是一种特殊的二叉树,除了最后一层外,每一层的节点数都是满的,并且最后一层的节点都靠左排列。我们可以使用层序遍历的思想来判断一棵二叉树是否为完全二叉树。具体步骤如下:

  1. 初始化一个队列。
  2. 将根节点入队。
  3. 当队列不为空时,取出队头节点,如果该节点为空,则停止检查。
  4. 否则,将该节点的左右子节点(不管是否为空)入队。
  5. 继续检查队列中剩余的节点,如果存在不为空的节点,则该二叉树不是完全二叉树。

以下是判断完全二叉树的代码实现(可以CV一下层序遍历的代码然后进行修改):

// BTree.cpp
// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
    Queue q;
    QueueInit(&q);
    if(root)
    {
        QueuePush(&q, root);
    }
    while(!QueueEmpty(&q))
    {
        BTNode* front = QueueFront(&q);
        QueuePop(&q);
        //检查到第一次空停止
        if(front == NULL)
        {
            break;
        }
        QueuePush(&q, front->left);
        QueuePush(&q, front->right);
    }
    //检测后面是否有不为空的数据,若有则返回false
    while(!QueueEmpty(&q))
    {
        BTNode* front = QueueFront(&q);
        QueuePop(&q);
        if(front)
        {
            QueueDestory(&q);
            return false;
        }
    }
    QueueDestory(&q);
    return true;
}

测试代码

在 Test.cpp 文件中,我们可以测试层序遍历和判断完全二叉树的功能:

// Test.cpp
#include "BTree.h"
#include "Queue.h"

int main()
{
    BTNode* root = BinaryTreeCreate();

    // 层序遍历
    BinaryTreeLevelOrder(root);
    printf("\n");

    // 二叉树是否为完全二叉树
    if(BinaryTreeComplete(root))
        printf("1");
    else
        printf("0");
    printf("\n");

    return 0;
}

总结

通过队列这种数据结构,我们可以很方便地实现二叉树的层序遍历和判断完全二叉树。层序遍历可以帮助我们按层次顺序访问二叉树的节点,而判断完全二叉树则可以帮助我们确定二叉树的结构特性。在实际应用中,这些操作都有着重要的作用。希望本文能帮助你更好地理解二叉树的层序遍历和完全二叉树的判断方法。

以上就是关于二叉树的层序遍历和完全二叉树判断的详细介绍,如果你有任何疑问或建议,欢迎在评论区留言。

你可能感兴趣的:(数据结构,二叉树,完全二叉树,层序遍历,c语言,队列)