数据结构 - 二叉树

200 阅读5分钟

在阅读本文前, 请先阅读以下两篇文章.

数据结构 - 单链表 - 掘金 (juejin.cn)

数据结构 - 队列 - 掘金 (juejin.cn)

一. 二叉树的定义 & 结构

二叉树的定义

image.png

一棵二叉树是节点的一个有限集合, 该集合或者为空, 或者由一个根节点加上两棵别称为左子树右子树的二叉树组成.

二叉树的结构

子结构

对于任意的二叉树都是由以下几种情况复合而成的.

image.png

特殊二叉树

满二叉树: 一个二叉树, 如果每一个层的节点数都达到最大值, 则这个二叉树就是满二叉树. 也就是说, 如果一个二叉树的层数为 K, 且节点总数是 2^K - 1, 则它就是满二叉树.

完全二叉树: 深度为 k, 有 n 个节点的二叉树当且仅当其每一个节点都与深度为 k 的满二叉树中编号从1 到 n 的节点一一对应时, 称其为完全二叉树.

image.png

二. 二叉树各种接口的实现

此处的二叉树采用链式存储的结构实现.

image.png

typedef int BTDataType;

typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;

1. 创建一个二叉树节点

BTNode* BuyNode(BTDataType x)
{
    BTNode* node = (BTNode*)malloc(sizeof(BTNode));
    if (node == NULL) {
        perror("malloc fail");
        return NULL;
    }

    node->data = x;
    node->left = NULL;
    node->right = NULL;

    return node;
}

2. 销毁二叉树

采用后序遍历(左右根)的方式销毁二叉树.

void TreeDestroy(BTNode* root)
{
    if (root == NULL) return;

    TreeDestroy(root->left); 
    TreeDestroy(root->right);
    free(root);
}

3. 前序遍历

前序遍历, 即访问根节点的操作发生在遍历其左右子树之前.

void PreOrder(BTNode* root)
{
    if (root == NULL) {
        printf("NULL ");
        return;
    }

    printf("%d ", root->data);
    PreOrder(root->left);
    PreOrder(root->right);
}

4. 中序遍历

中序遍历, 即访问根节点的操作发生在遍历其左右子树之中.

void InOrder(BTNode* root)
{
    if (root == NULL) { 
        printf("NULL "); 
        return;
    }

    InOrder(root->left); 
    printf("%d ", root->data);
    InOrder(root->right); 
}

5. 后序遍历

后序遍历, 即访问根节点的操作发生在遍历其左右子树之后.

void PostOrder(BTNode* root)
{
    if (root == NULL) {
        printf("NULL ");
        return;
    }

    PostOrder(root->left); 
    PostOrder(root->right); 
    printf("%d ", root->data);
}

6. 二叉树节点个数

int TreeSize(BTNode* root)
{
    return root == NULL ? 0 :
        TreeSize(root->left)
        + TreeSize(root->right)
        + 1;
}

7. 二叉树高度

int TreeHeight(BTNode* root)
{
    if (root == NULL) return 0;

    int leftHeight = TreeHeight(root->left);
    int rightHeight = TreeHeight(root->right);

    return leftHeight > rightHeight ?
        leftHeight + 1 : rightHeight + 1;
}

8. 二叉树第k层节点个数

int TreeLevelKSize(BTNode* root, int k)
{
    assert(k > 0);

    if (root == NULL) return 0;

    if (k == 1) return 1;

    return TreeLevelKSize(root->left, k - 1)
        + TreeLevelKSize(root->right, k - 1);
}

9. 查找值为 x 的节点

BTNode* TreeFind(BTNode* root, BTDataType x)
{
    if (root == NULL) return NULL;

    if (root->data == x) return root;

    BTNode* lret = TreeFind(root->left, x);
    if (lret) return lret;

    BTNode* rret = TreeFind(root->right, x);
    if (rret) return rret;

    return NULL;
}

将 Queue.h 中的 typedef int QDataType; 改为 typedef struct BinaryTreeNode* QDataType;

10. 层序遍历

根节点不为空, 执行 if 语句的内容.

QueuePush(&q, root);

image.png

队列不为空, 进入 while 循环.

BTNode* front = QueueFront(&q);

image.png

QueuePop(&q);

image.png

printf("%d ", front->data);

image.png

front 节点左孩子不为空, 将左孩子入队.

QueuePush(&q, front->left);

image.png

front 节点右孩子不为空, 将右孩子入队.

QueuePush(&q, front->right);

image.png

重复这一步骤, 直至队列为空.

image.png

void LevelOrder(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);
        }
    }

    QueueDestroy(&q);
}

11. 判断二叉树是否是完全二叉树

bool TreeComplete(BTNode* root)
{
    Queue q;
    QueueInit(&q);
    if (root) QueuePush(&q, root);

    while (!QueueEmpty(&q)) {
        BTNode* front = QueueFront(&q);
        QueuePop(&q);

        if (front == NULL) {
            break;
        } else {
            QueuePush(&q, front->left); 
            QueuePush(&q, front->right);
        }
    }

    // 开始判断是否是完全二叉树
    while (!QueueEmpty(&q)) {
        BTNode* front = QueueFront(&q);
        QueuePop(&q);

        // 出现非空节点, 说明非空节点不连续
        if (front) {
            QueueDestroy(&q);
            return false;
        }
    }

    QueueDestroy(&q);   
    return true;
}

三. 二叉树的源码

BinaryTree.h

#pragma once
#include "Queue.h"

typedef int BTDataType;

typedef struct BinaryTreeNode
{
    BTDataType data;    // 数据域
    struct BinaryTreeNode* left;    // 左孩子
    struct BinaryTreeNode* right;    // 右孩子
}BTNode;

// 创建一个二叉树节点
BTNode* BuyNode(BTDataType x);

// 销毁二叉树
void TreeDestroy(BTNode* root);

// 前序遍历
void PreOrder(BTNode* root);

// 中序遍历
void InOrder(BTNode* root);

// 后序遍历
void PostOrder(BTNode* root);

// 二叉树节点个数
int TreeSize(BTNode* root);

// 二叉树高度
int TreeHeight(BTNode* root);

// 二叉树第k层节点个数
int TreeLevelKSize(BTNode* root, int k);

// 查找值为 x 的节点
BTNode* TreeFind(BTNode* root, BTDataType x);

// 层序遍历
void LevelOrder(BTNode* root);   

// 判断二叉树是否是完全二叉树
bool TreeComplete(BTNode* root);

BinaryTree.c

#include "BinaryTree.h"

BTNode* BuyNode(BTDataType x)
{
    BTNode* node = (BTNode*)malloc(sizeof(BTNode));
    if (node == NULL) {
        perror("malloc fail");
        return NULL;
    }

    node->data = x;
    node->left = NULL;
    node->right = NULL;

    return node;
}

void TreeDestroy(BTNode* root)
{
    if (root == NULL) return;

    TreeDestroy(root->left); 
    TreeDestroy(root->right);
    free(root);
}

void PreOrder(BTNode* root)
{
    if (root == NULL) {
        printf("NULL ");
        return;
    }

    printf("%d ", root->data);
    PreOrder(root->left);
    PreOrder(root->right);
}

void InOrder(BTNode* root)
{
    if (root == NULL) { 
        printf("NULL "); 
        return;
    }

    InOrder(root->left); 
    printf("%d ", root->data);
    InOrder(root->right); 
}

void PostOrder(BTNode* root)
{
    if (root == NULL) {
        printf("NULL ");
        return;
    }

    PostOrder(root->left); 
    PostOrder(root->right); 
    printf("%d ", root->data);
}

int TreeSize(BTNode* root)
{
    return root == NULL ? 0 :
        TreeSize(root->left)
        + TreeSize(root->right)
        + 1;
}

int TreeHeight(BTNode* root)
{
    if (root == NULL) return 0;

    int leftHeight = TreeHeight(root->left);
    int rightHeight = TreeHeight(root->right);

    return leftHeight > rightHeight ?
        leftHeight + 1 : rightHeight + 1;
}

int TreeLevelKSize(BTNode* root, int k)
{
    assert(k > 0);

    if (root == NULL) return 0;

    if (k == 1) return 1;

    return TreeLevelKSize(root->left, k - 1)
        + TreeLevelKSize(root->right, k - 1);
}

BTNode* TreeFind(BTNode* root, BTDataType x)
{
    if (root == NULL) return NULL;

    if (root->data == x) return root;

    BTNode* lret = TreeFind(root->left, x);
    if (lret) return lret;

    BTNode* rret = TreeFind(root->right, x);
    if (rret) return rret;

    return NULL;
}

void LevelOrder(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);
        }
    }

    QueueDestroy(&q);
}

bool TreeComplete(BTNode* root)
{
    Queue q;
    QueueInit(&q);
    if (root) QueuePush(&q, root);

    while (!QueueEmpty(&q)) {
        BTNode* front = QueueFront(&q);
        QueuePop(&q);

        if (front == NULL) {
            break;
        } else {
            QueuePush(&q, front->left); 
            QueuePush(&q, front->right);
        }
    }

    // 开始判断是否是完全二叉树
    while (!QueueEmpty(&q)) {
        BTNode* front = QueueFront(&q);
        QueuePop(&q);

        // 出现非空节点, 说明非空节点不连续
        if (front) {
            QueueDestroy(&q);
            return false;
        }
    }

    QueueDestroy(&q);   
    return true;
}