每日一题-判断是不是完全二叉树

判断是否是完全二叉树

题目

描述

给定一个二叉树,判断它是否是一个完全二叉树。

完全二叉树的定义

若二叉树的深度为 h h h,除了第 h h h 层外,其它各层的节点数都达到最大个数,第 h h h 层所有的叶子节点都连续集中在最左边,这就是完全二叉树。第 h h h 层可能包含 [ 1 2 h ] [1~2^h] [1 2h] 个节点。

数据范围

  • 节点数: 1 ≤ n ≤ 100 1 \leq n \leq 100 1≤n≤100

示例

示例 1

输入

复制代码
{1, 2, 3, 4, 5, 6}

输出

复制代码
true

示例 2

输入

复制代码
{1, 2, 3, 4, 5, 6, 7}

输出

复制代码
true

示例 3

输入

复制代码
{1, 2, 3, 4, 5, #, 6}

输出

复制代码
false

题解

思路

完全二叉树的判断方法可以通过层序遍历(广度优先遍历)来实现:

  • 层序遍历过程中,如果遇到某个节点的左右子节点为空,但后续节点仍然存在,则说明该二叉树不是完全二叉树。
  • 也就是说,在遇到一个空节点后,后面所有节点必须也是空节点,否则就违反了完全二叉树的定义。

算法步骤

  1. 使用队列进行层序遍历,遍历每一个节点。
  2. 如果节点为空,标记为已遇到空节点。
  3. 如果节点非空,但已经遇到过空节点,则返回 false,因为在空节点之后应该没有非空节点。
  4. 如果层序遍历完毕,且没有违反完全二叉树的条件,则返回 true

代码实现

c 复制代码
#include <stdlib.h>
#include <stdbool.h>

/**
 * 结构体定义
 * struct TreeNode {
 *  int val;
 *  struct TreeNode *left;
 *  struct TreeNode *right;
 * };
 */

/**
 * 队列结构体
 */
typedef struct {
    struct TreeNode** data;
    int front;
    int rear;
    int capacity;
} queue;

/**
 * 创建队列
 */
queue* createQueue(int capacity) {
    queue* q = (queue*)malloc(sizeof(queue));
    q->data = (struct TreeNode**)malloc(capacity * sizeof(struct TreeNode*));
    q->front = 0;
    q->rear = 0;
    q->capacity = capacity;
    return q;
}

/**
 * 判断队列是否为空
 */
bool isEmpty(queue* q) {
    return q->front == q->rear;
}

/**
 * 从队列中弹出元素
 */
struct TreeNode* pop(queue* q) {
    return q->data[q->front++];
}

/**
 * 将节点插入队列
 */
void push(queue* q, struct TreeNode* node) {
    if (q->rear < q->capacity) {
        q->data[q->rear++] = node;
    }
}

/**
 * 释放队列内存
 */
void freeQueue(queue* q) {
    free(q->data);
    free(q);
}

/**
 * 判断二叉树是否是完全二叉树
 */
bool isCompleteTree(struct TreeNode* root) {
    if (root == NULL) {
        return true; // 空树是完全二叉树
    }

    queue* q = createQueue(1000); // 创建队列用于层序遍历
    bool flag = false; // 标记是否已遇到空节点
    push(q, root); // 将根节点入队

    while (!isEmpty(q)) {
        struct TreeNode* current = pop(q); // 弹出队列中的节点
        
        if (current == NULL) {
            flag = true; // 遇到空节点,标记为true
        } else {
            if (flag) {
                return false; // 如果之前遇到过空节点,现在还遇到非空节点,则返回false
            }
            push(q, current->left);  // 左子节点入队
            push(q, current->right); // 右子节点入队
        }
    }

    freeQueue(q); // 释放队列
    return true; // 完全二叉树
}

代码解释

  1. 队列操作

    • 定义了一个队列 queue,用于层序遍历二叉树。
    • 使用 push 函数将节点入队,pop 函数从队列中弹出节点。
    • 使用 isEmpty 函数判断队列是否为空。
  2. isCompleteTree 函数

    • 使用队列进行层序遍历。
    • 如果当前节点为 NULL,则说明该节点为空节点,标记 flagtrue
    • 如果在遇到空节点后还遇到非空节点,说明该二叉树不满足完全二叉树的定义,返回 false
    • 如果遍历完成后没有违反完全二叉树的规则,返回 true

复杂度分析

  • 时间复杂度 : O ( n ) O(n) O(n),每个节点被访问一次。
  • 空间复杂度 : O ( n ) O(n) O(n),队列的空间复杂度最坏情况下为树的最大宽度。

总结

这题本质上就是通过层序遍历(广度优先遍历)结合标记法,判断树是否满足完全二叉树的条件。关键在于,遇到空节点后,后续所有节点必须也是空节点,否则就不满足完全二叉树的定义。主要考察对于层序遍历的应用。当然这题最难的还是如何用C语言实现一个队列。确实还是C++方便,直接用

相关推荐
Dann Hiroaki17 分钟前
文献分享: 对ColBERT段落多向量的剪枝——基于学习的方法
学习·算法·剪枝
三三木木七22 分钟前
神经网络的基本知识
人工智能·神经网络·算法
_extraordinary_23 分钟前
穷举vs暴搜vs深搜vs回溯vs剪枝刷题 + 总结
算法·深度优先·剪枝
studyer_domi27 分钟前
matlab 三维桥式起重机系统数学模型
人工智能·算法·matlab
不如画七43 分钟前
代码随想录-04-字符串-03.替换数字
数据结构·字符串
曦月逸霜43 分钟前
第十次CCF-CSP认证(含C++源码)
数据结构·c++·算法·ccf-csp
滨HI01 小时前
1314:【例3.6】过河卒(Noip2002)--DP>DFS【超时DFS】
算法·深度优先
Y编程小白1 小时前
JVM--垃圾回收
jvm·算法
KhalilRuan1 小时前
代码随想录-训练营-day52
算法
nqqcat~2 小时前
函数的引用/函数的默认参数/函数的占位参数/函数重载
开发语言·c++·算法