数据结构——链式结构二叉树

目录

一、二叉树的链式结构

二、手动创建一棵链式二叉树

[三、 二叉树的遍历](#三、 二叉树的遍历)

(1)前序遍历(先序遍历)

(2)中序遍历

(3)后序遍历

四、二叉树的有关函数

(1)头文件

(2)二叉树结点总数

[(3) 二叉树叶子结点个数](#(3) 二叉树叶子结点个数)

[(4) 二叉树第k层结点个数](#(4) 二叉树第k层结点个数)

(5)二叉树的高度/深度

[(6) 二叉树查找值为x的结点](#(6) 二叉树查找值为x的结点)

(7)二叉树的销毁

五、层序遍历

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

七、写在最后


一、二叉树的链式结构

链表来表示二叉树,其实就是用链来指示元素的逻辑关系

链表中的每个结点由3个域组成:数据域和左右指针域,其中左右指针分别用来给出该结点左孩子和右孩子所在链的结点的存储地址。

cpp 复制代码
typedef int BTDatatype;
//二叉链
typedef struct BinaryTreeNode
{
    BTDatatype val;//当前结点的值域
    struct BinaryTreeNode* left;//指向当前结点的左孩子
    struct BinaryTreeNode* right;//指向当前结点的右孩子

}

二、手动创建一棵链式二叉树

二叉树分为空树和非空二叉树,其中非空二叉树由根结点、根结点的左孩子和根结点的右孩子组成。而根结点的左右子树又是由子树结点、子树结点的左孩子和子树结点的右孩子组成的,因此二叉树的定义是递归的。

cpp 复制代码
//创建新结点
BTNode* BuyNode(int val)
{
    BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
    if(newnode == NULL)
    {
        perror("malloc fail!");
        reutrn NULL;
    }
    newnode->val = val;
    newnode->left = newnode->right = NULL;
    return newnode;
}

//创建二叉树
BTNode* CreatTree()
{
    BTNode* n1 = BuyNode(1);
    BTNode* n2 = BuyNode(2);
    BTNode* n3 = BuyNode(3);
    BTNode* n4 = BuyNode(4);
    BTNode* n5 = BuyNode(5);
    BTNode* n6 = BuyNode(6);
    BTNode* n7 = BuyNode(7);

    n1->left = n2;
    n1->right = n4;
    n2->left = n3;
    n4->left = n5;
    n4->right = n6;
    n5->left = n7;

    return n1;

}

三、 二叉树的遍历

(1)前序遍历(先序遍历)

访问根结点 的操作发生在遍历其左右子树之

访问顺序为:根结点、左子树、右子树,即:根左右

cpp 复制代码
void PerOrder(BTNode* root)
{
    //若根结点为空,直接返回
    if(root == NULL)
    {
        printf("NULL");
        return;
    }
    //先打印根结点的数据
    printf("%d ",root->val);
    //遍历左孩子
    PerOrder(root->left);
    //遍历右孩子
    PerOrder(root->right);
}

(2)中序遍历

访问根结点的操作发生在遍历其左右子树之(间);

访问顺序为:左子树、根结点、右子树,即:左根右

cpp 复制代码
void InOrder(BTNode* root)
{
    if(root == NULL)
    {
        printf("NULL");
        return;
    }
    InOrder(root->left);
    printf("%d ",root->val);
    InOrder(root->right);
}

(3)后序遍历

访问根结点的操作发生在遍历其左右子树之

访问顺序为:左子树、右子树、根结点,即:左右根

cpp 复制代码
void PostOrder(BTNode* root)
{
    if(root == NULL)
    {
        printf("NULL");
        return;
    }
    PostOrder(root->left);
    PostOrder(root->right);
    printf("%d ",root->val);
}

四、二叉树的有关函数

(1)头文件

cpp 复制代码
// ⼆叉树结点总数 
int BinaryTreeSize(BTNode* root);
 
// ⼆叉树叶⼦结点个数 
int BinaryTreeLeafSize(BTNode* root); 

// ⼆叉树第k层结点个数 
int BinaryTreeLevelKSize(BTNode* root, int k); 

//⼆叉树的深度/⾼度
int BinaryTreeDepth(BTNode* root);

// ⼆叉树查找值为x的结点 
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);

// ⼆叉树的销毁
void BinaryTreeDestory(BTNode** root);

(2)二叉树结点总数

cpp 复制代码
int BinaryTreeSize(BTNode* root)
{
    if(root == NULL)
    {
        return 0;
    }
    //根结点+左子树中结点的个数+右子树中结点的个数
    return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}

(3) 二叉树叶子结点个数

cpp 复制代码
int BinaryTreeLeafSize(BTNode* root)
{
    if(root == NULL)
    {
        return 0;
    }
    //没有左右孩子结点,即为叶子结点
    if(root->left == NULL && root->right == NULL)
    {
        return 1;
    }
    //左子树的叶子结点数+右子树的叶子结点数
    return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}

(4) 二叉树第k层结点个数

cpp 复制代码
int BinaryTreeLevelKSize(BTNode* root, int k)
{
    if(root == NULL)
    {
        return 0;
    }
    //第k层
    if(k == 1)
    {
        return 1;
    }
    //左子树的第k层结点数+右子树的第k层结点数
    return BinaryTreeLevelKSize(root->left, k-1) + BinaryTreeLevelKSize(root->right, k-1);
}

(5)二叉树的高度/深度

cpp 复制代码
int BinaryTreeDepth(BTNode* root)
{
    if(root == NULL)
    {
        return 0;
    }
    //分别求得左右子树的深度
    int leftDeep = BinaryTreeDepth(root->left);
    int rightDeep = BinaryTreeDepth(root->right);
    //根结点 + 左右子树的深度的最大值
    return leftDeep > rightDeep ? leftDeep + 1 : rightDeep + 1;
}

(6) 二叉树查找值为x的结点

cpp 复制代码
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
    if(root == NULL)
    {
        return  NULL;
    }
    找到值为x的数据
    if(root->val == x)
    {
        return root;
    }
    //在左子树中找值为x的数据
    //如果在左子树找到,直接返回,无需在右子树寻找
    BTNode* leftFind = BinaryTreeFind(root->left, x);
    if(leftFind)
    {
        return leftFind;
    }

    BTNode* rightFind = BinaryTreeFind(root->right, x);
    if(rightFind)
    {
        return rightFind;
    }
    如若在左右子树都没有找到,则说明找不到
    return NULL;
}

(7)二叉树的销毁

cpp 复制代码
//注意传入的是指针的地址,形参为二级指针
void BinaryTreeDestory(BTNode** root)
{
    if(*root == NULL)
    {
        return;
    }
    //销毁左右子树
    BinaryTreeDestory(&((*root)->left));
    BinaryTreeDestory(&((*root)->right));
    //销毁根结点
    free(*root);
    *root = NULL;
}

五、层序遍历

设⼆叉树的根结点所在层数为1,层序遍历就是从所在⼆叉树的根结点 出发,首先访问第⼀层的树根结点,然后从左到右 访问第2层上的结点,接着是第三层的结点,以此类推,自上而下,从左至右逐层访问树的结点的过程。

实现层序遍历需要额外借助数据结构:队列。

cpp 复制代码
void LevelOrder(BTNode* root)
{
    Queue q;
    QueueInit(&q);
    QueuePush(&q, root);
    while(!QueueEmpty(&q))
    {
        //取队头,并打印
        BTNode* front = QueueFront(&q);
        printf("%d ",front->val);

        //队头结点的左右孩子入队列
        if(front->left)
        {
            QueuePush(&q, front->left);
        }
        if(front->right)
        {
            QueuePush(&q, front->rught);
        }
    }
    //此时队列为空,销毁队列
    QueueDestroy(&q);
}

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

cpp 复制代码
bool BinaryTreeComplete(BTNode* root) 
{
    Queue q;
    QueueInit(&q);
    QueuePush(&q, root);
    while (!QueueEmpty(&q))
    {
        BTNode* top = QueueFront(&q);
        QueuePop(&q);
        if (top == NULL) 
        {
            break;
        }
        QueuePush(&q, top->_left);
        QueuePush(&q, top->_right);
    }
    //队列不一定为空
    while (!QueueEmpty(&q))
    {
        BTNode* top = QueueFront(&q);
        QueuePop(&q);
        if (top != NULL) 
        {
            QueueDesTroy(&q);
            return false;
        }
    }
    QueueDesTroy(&q);
    return true;
}

如果是完全二叉树,跳出一个循环之后队列中剩下的全都是NULL结点;

如果不是完全二叉树,跳出一个循环之后队列中还有非空结点。

七、写在最后

我们已经学习了实现二叉树的两种方法:顺序结构(堆)和链式结构。

敬请期待"二叉树OJ题"~

相关推荐
黑听人43 分钟前
【力扣 中等 C++】90. 子集 II
开发语言·数据结构·c++·算法·leetcode
黑听人1 小时前
【力扣 简单 C】21. 合并两个有序链表
c语言·开发语言·数据结构·算法·leetcode
ling__wx2 小时前
go部分语法记录
数据结构
黑听人2 小时前
【力扣 简单 C】83. 删除排序链表中的重复元素
c语言·开发语言·数据结构·算法·leetcode
怀旧,4 小时前
【数据结构】7. 栈和队列
数据结构
彷徨而立4 小时前
【C/C++】创建文件夹
c语言·开发语言·c++
程序猿小D6 小时前
第30节 Node.js C/C++ 插件
c语言·c++·后端·node.js·vim
W说编程6 小时前
算法导论第一章:算法基础与排序艺术
c语言·数据结构·算法
titan TV man6 小时前
上海市计算机学会竞赛平台2022年5月月赛丙组最远城市距离
数据结构·算法
慢半拍iii14 小时前
数据结构——D/串
c语言·开发语言·数据结构·c++