几分钟搞定队数据结构在非递归层序遍历算法中的应用

来源:互联网 发布:阿里云高校工作坊 编辑:程序博客网 时间:2024/04/27 15:02

研究队数据结构在层序遍历算法的应用之前:

我们先需要了解几个基本知识,首先队数据结构是什么,有什么特性也就是不同点。
首先队数据结构其实也就是数据类型,只是这个数据类型里面在堆上开了一定的内存,可以保存大量的元素,

其次进入的元素,当前我们想要取保存的元素不能像数组类型那样根据下标任意的取数据元素。
队数据结构只给我们提供了pop操作和Push操作,底层代码其实是在内存两端进行操作的。

层级遍历又是什么呢。首先先看二叉树的图,因为我们的层级遍历算法目前是参照的二叉树来说的。

这里写图片描述

如果你不熟悉上图是什么东西,请去复习在继续看,

下面层序遍历是什么呢,也就是假如我们对这个二叉树进行层级遍历算法后里面的元素输出是什么样的。

我们默认是把这棵二叉树从根节点开始编号为A =1 然后往下 到了第二层 在从左到右编号 B = 2 C = 3

D = 4 ………….直到H =9.

在这里这个编号没啥作用,只是告诉我们这个节点字母有个顺序,其实我们的层序遍历就是按照这个编号次序输出里面的字母:我写下层序遍历后的结果: ABCDEFGIEH

所以我们想要中序遍历算法又不是递归需要输出这个序列:

假如我们不单独开内存保存一些数据,我们会一次性全部访问到吗,

我来分析下:假如我得到了根节点A的地址,那么我就输出这个A里面的内容,然后通过A得到A的孩子节点可以输出A的孩子节点B,如果说我们的A地址不临时开始内存去保存下,那么我们怎么样去找到B孩子节点。可以是可以我们可以从头A在开始得到右孩子节点,话说你这样做是什么情况,同样的数据需要重复去读取。这个在编程上效率很低。

现在大家发现了一个关键点,我们如果不用递归就没有递归这个特性可以保存我们的上下文,也就是上次执行的位置的全部信息,就是不会回退。

那么我们就需要自己去动手保存当前访问节点的上次节点信息。
我们发现每次访问完一个节点必须保存很多数据,出不至于从头在来。

我具体拿一个数据分析:

这里写图片描述

假如我们访问A节点,我们就开个变量保存下A,接着我们通过A访问B节点,这个时候我必须把B节点也保存,不然会出现我们通过保存的A节点访问了c节点后,没法访问D节点,因此我们既然保存了B节点,我们就通过B节点访问D,一直循环下来就搞定。

现在引入队数据结构:

我们会发现上面先开内存保存的变量是先被访问的,是不是和我们的队数据结构很多像,先存的先访问,
并且上面开的数据内存是离散的。我们用队数据结构开,就可以把这些临时数据搞到一起,方便访问,

下面来分析通过队数据结构的示意图:

这里写图片描述

上图2个横线间的空间假如我们看出栈内存,可以放我们的根节点。

后面是需要层序遍历的二叉树:

下面开始使用队列进行层序遍历
这里写图片描述

首先我先把根节点入队

然后我就开始循环访问输出
这里写图片描述

发现没,我是先输出A节点的元素,在把A节点左右孩子节点按照次序入队。

然后在把左孩子B出队并且输出元素,在把他的孩子入入队列也就是放在队尾部

图

如此循环下去全部元素输出一定是层序遍历后面的结果;

下面进入代码阶段:
还是类似伪代码:

//使用队列数据结构进行的层序遍历算法   注意:没有用递归以及针对二叉树  BT是二叉树的根节点地址void LevelOrderTraversal(BinTree BT){     //定义算法需要的一些临时变量      Queue Q, BinTree T;   //Q变量是用来保存我们的队数据结构内存首地址 T保存出队后的节点元素地址    //我还是提前判断给我根节点地址是不是为null把,如果为null就早点退出,以免执行无用的代码,其实应该放第一行的。   if(BT == null) return;  //没有数据了那么我就退出这个算法   //开始开队列数据结构内存,默认初始内存大小为MaxSize   Q = CreateQueue(MaxSize);   //默认成功了吧就不判断了   //既然有了队列 我们就入队保存数据   Q.Push(BT);    //根节点先入队   //注释:我们输出节点元素其实就在队中出栈输出的,因此我们可以写个死循环一直出队,只直到队出完就结束   while(!Q.Empty) //表示队还有元素就执行循环   {       //我们这个时候是想输出根节点,刚好入队了,那么我们出队列就可以       T = Q.pop(); //出队了,并且队中没有当前这个元素了,并且我们需要保存下,有其他操作,       //现在我们就可以输出节点里的内容       printf("%d",T->data);       //现在我们想输出他的孩子,节点,又得入队,当然我们必须先判断是不是有孩子啊       if(T->lChild != null)         Q.Push(T->lChild);  //左孩子入队       //我们把右孩子也入队   记住右孩子是后入队肯定是后面输出的       if(T->rChild != null)          Q.Push(T->rChild); //右孩子入队       //代码已经结束,因为是循环。   }}
阅读全文
0 0