目录
一、引言
✨ 欢迎来到二叉树的知识的第二讲!在上一篇文章中,我们主要通过递归的方式介绍了遍历二叉树,创建二叉树,数据查找,判断树的深度等基本功能,同时也卖了很多关子,(一直说着栈和队列有多好用却一直不用哈哈哈),那么本章我们就把栈和队列应用起来,见识见识它们的强大之处!
二、使用栈前序遍历二叉树
(一)原材料
在之前我发过一篇栈的博客,懒得重新手打一遍的可以直接CV,把栈存储的数据类型改一改即可(这里我也建议大家有一个自己的库函数,准备好其功能函数在需要的时候就可以直接CV,节省时间,这也是CV工程师的基本修养)。
(二)逻辑结构
这是上一篇中前序遍历的顺序图
先通过我的理解简单说一下为什么要用栈:
前序遍历从根节点
A
开始访问,A 的左右子树分别为B、C
,按照前序遍历,我们应该先访问B
,那么我们就该把C
存储起来,访问B
后,发现B的左右子树为D、E
,把E
储存起来,然后访问D
后发现D
的左右子树为H、I
,同样把I储存起来,访问H
,这样一路下来发现没有左子树可以访问了,此时我们已经依次存储了C、E、I
,按前序遍历顺序我们应该先访问I
,诶?!🧐后出现的先访问,这不就是栈嘛!
依照上面的说法,访问相当于出栈的操作,而存储则相当于进栈。那么代码的逻辑结构是:
-
先将根节点入栈
-
弹出栈顶元素,依次将该节点的右子树、左子树进栈
-
重复(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
,先出现的先访问,因此我们用到队列
逻辑结构如下:
-
根节点入队列
-
根节点出队列,并依次讲其左右子树入队列
-
重复(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;
}
代码逻辑如下:
本篇文章介绍了栈和队列在二叉树中的实际应用,在下一章节我们将讨论有序二叉树以及哈夫曼编码,感谢支持!
最后感谢你观看完我的文章,如果文章对你有帮助,可以点赞收藏评论,这是对作者最好的鼓励!不胜感激🥰