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

判断是否是完全二叉树

题目

描述

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

完全二叉树的定义

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

相关推荐
YuTaoShao2 小时前
【LeetCode 热题 100】141. 环形链表——快慢指针
java·算法·leetcode·链表
小小小新人121233 小时前
C语言 ATM (4)
c语言·开发语言·算法
你的冰西瓜3 小时前
C++排序算法全解析(加强版)
c++·算法·排序算法
এ᭄画画的北北3 小时前
力扣-31.下一个排列
算法·leetcode
绝无仅有4 小时前
企微审批对接错误与解决方案
后端·算法·架构
用户5040827858395 小时前
1. RAG 权威指南:从本地实现到生产级优化的全面实践
算法
Python×CATIA工业智造6 小时前
详细页智能解析算法:洞悉海量页面数据的核心技术
爬虫·算法·pycharm
无聊的小坏坏7 小时前
力扣 239 题:滑动窗口最大值的两种高效解法
c++·算法·leetcode
黎明smaly7 小时前
【排序】插入排序
c语言·开发语言·数据结构·c++·算法·排序算法