【数据结构】六、栈和队列在二叉树中的使用

目录

一、引言

二、使用栈前序遍历二叉树

(一)原材料

(二)逻辑结构

(三)代码实现

三、使用队列层序遍历二叉树

(一)同样可以CV

(二)逻辑结构

(三)代码实现

四、判断一棵树是否为完全二叉树


一、引言

✨  欢迎来到二叉树的知识的第二讲!在上一篇文章中,我们主要通过递归的方式介绍了遍历二叉树,创建二叉树,数据查找,判断树的深度等基本功能,同时也卖了很多关子,(一直说着栈和队列有多好用却一直不用哈哈哈),那么本章我们就把栈和队列应用起来,见识见识它们的强大之处!

二、使用栈前序遍历二叉树

(一)原材料

在之前我发过一篇栈的博客,懒得重新手打一遍的可以直接CV,把栈存储的数据类型改一改即可(这里我也建议大家有一个自己的库函数,准备好其功能函数在需要的时候就可以直接CV,节省时间,这也是CV工程师的基本修养)。

【数据结构】三、栈和链栈-优快云博客

(二)逻辑结构

这是上一篇中前序遍历的顺序图

先通过我的理解简单说一下为什么要用栈:

前序遍历从根节点 A开始访问A 的左右子树分别为 B、C,按照前序遍历,我们应该先访问B,那么我们就该把 C 存储起来,访问B后,发现B的左右子树为 D、E,把 E储存起来,然后访问D后发现D的左右子树为H、I,同样把I储存起来,访问H,这样一路下来发现没有左子树可以访问了,此时我们已经依次存储了C、E、I,按前序遍历顺序我们应该先访问I,诶?!🧐后出现的先访问,这不就是栈嘛

依照上面的说法,访问相当于出栈的操作,而存储则相当于进栈。那么代码的逻辑结构是:

  1. 先将根节点入栈

  2. 弹出栈顶元素,依次将该节点的右子树、左子树进栈

  3. 重复(2)的操作,直到栈为空

(三)代码实现
//使用栈前序遍历二叉树
void Stack_Preorder(BinTree* T)
{
    //定义一个栈,其实就是普通的栈改了个名字,把存储的数据类型改为BinTree
    Stack_Tree S;       
    //初始化栈
    StackTree_Init(&S);
    //根节点入栈
    StackTree_Push(&S, T);

    while (!StackTree_Empty(S))  //循环判断栈是否为空
    {
        BinTree* t = StackTree_Pop(&S); //出栈(访问栈顶元素)
        printf("%c ", t->data);

        if (t->rchile != NULL)
            StackTree_Push(&S, t->rchile); //右子树入栈
        if (t->lchile != NULL)
            StackTree_Push(&S, t->lchile); //左子树入栈
    }
    printf("\n");
}

三、使用队列层序遍历二叉树

(一)同样可以CV

【数据结构】四、循环队列、链式队列的理解和C代码实现-优快云博客

(二)逻辑结构

我们还是照着图来讲:

按照先序遍历,我们需要先访问根节点A,然后依次访问其左右子树B、C,既然先访问左子树B,那么我们要把C存储起来,访问完B后发现它有子树D、E,但是我们应该先去访问C再回来访问D、E先出现的先访问,因此我们用到队列

逻辑结构如下:

  1. 根节点入队列

  2. 根节点出队列,并依次讲其左右子树入队列

  3. 重复(2)的操作,直到队列为空

(三)代码实现
//使用队列层序遍历二叉树
void SequenceTraversal(BinTree* T)
{
    //同样是使用普通队列,讲数据类型改为BinTree
    Queue_Tree Q;
    //初始化
    QueueTree_Init(&Q);
    //根节点入队列
    QueueTree_Add(&Q, T);

    while (!QueueTree_Empty(Q))
    {
        BinTree* t = QueueTree_Pop(&Q);
        visit(t);                         //访问队头元素
        if (t->lchile != NULL)
            QueueTree_Add(&Q, t->lchile); //左子树入队列
        if (t->rchile != NULL)
            QueueTree_Add(&Q, t->rchile); //右子树入队列
    }
}

四、判断一棵树是否为完全二叉树

复习一下,完全二叉树的所有层级都被完全填充,除了最下面一层的节点从尽可能左侧填充,很明显要使用层序遍历。

如何操作呢?很简单,先找出第一个叶子节点或者只有左子树没有右子树的节点,并且该节点之后全部为叶子节点的树就是完全二叉树。

//判断是否为完全二叉树
int JudgeCompleBintree(BinTree* T)
{
    Queue_Tree Q;
    QueueTree_Init(&Q);
    QueueTree_Add(&Q, T);
    int i = 0;
    while (!QueueTree_Empty(Q))
    {
        BinTree* t = QueueTree_Pop(&Q);
        if(i && (t->lchile!=NULL || t->rchile != NULL)) //找到第一个非满节点后,判断之后的是否全部为叶子节点
            i = 2;
        if (t->lchile != NULL)
            QueueTree_Add(&Q, t->lchile);
        if (t->rchile != NULL)
            QueueTree_Add(&Q, t->rchile);
        //找到第一个叶子节点或者只有左子树没有右子树的节点
        if (i == 0 && (t->lchile == NULL && t->rchile == NULL) || (t->lchile == NULL && t->rchile != NULL))
        {
            i = 1;
        }
        //如果找到的第一个非满节点只有右子树而没有左子树,则不是完全二叉树
        else if (i == 0 && (t->lchile == NULL && t->rchile != NULL))
            break;
    }
    if (i == 1) return 1;
    else return 0;
}

代码逻辑如下:

本篇文章介绍了栈和队列在二叉树中的实际应用,在下一章节我们将讨论有序二叉树以及哈夫曼编码,感谢支持!

最后感谢你观看完我的文章,如果文章对你有帮助,可以点赞收藏评论,这是对作者最好的鼓励!不胜感激🥰

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值