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

判断是否是完全二叉树

题目

描述

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

完全二叉树的定义

若二叉树的深度为 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++方便,直接用

相关推荐
地平线开发者1 小时前
征程 6 | linear 高精度输出配置方式
算法·自动驾驶
小尧嵌入式1 小时前
C++基础语法总结
开发语言·c++·stm32·单片机·嵌入式硬件·算法
white-persist1 小时前
【攻防世界】reverse | IgniteMe 详细题解 WP
c语言·汇编·数据结构·c++·python·算法·网络安全
稚辉君.MCA_P8_Java1 小时前
Gemini永久会员 归并排序(Merge Sort) 基于分治思想(Divide and Conquer)的高效排序算法
java·linux·算法·spring·排序算法
地平线开发者2 小时前
征程 6 | QAT 新版 qconfig 量化模板使用教程
算法·自动驾驶
多恩Stone2 小时前
【ModelScope-1】数据集稀疏检出(Sparse Checkout)来下载指定目录
人工智能·python·算法·aigc
山峰哥2 小时前
沉浸式翻译插件深度评测:打破语言壁垒的黑科技利器
数据结构·科技·算法·编辑器·办公
AI脚下的巨人2 小时前
机器人逆运动学:从SVD到IK算法
算法·机器人
ゞ 正在缓冲99%…3 小时前
2025.9.28华为软开
算法·华为
9ilk3 小时前
【C++】 --- 哈希
c++·后端·算法·哈希算法