假设以带头结点的循环链表表示队列_数据结构——线性结构(4)——栈和队列的链式表示...

前篇讨论了一下具体的链表结构以及常规操作。现在我们趁热打铁,感觉再来熟悉一下具体的操作。此时我们用链表的形式来实现之前的顺序栈。

链栈

栈结构这里不多说,我们直接进入正题。先考虑,当栈为空的时候,如何表示?当然就是一个空指针了

f07b86c2e517ff5b3ff6bbab46a4b528.png

将新元素推入堆栈时,该元素只会添加到链表的前端。因此,如果将元素e1 push到空栈上,该元素将存储在一个新单元格中,该单元格将成为链中唯一的链接:

5b465544aa92ec1bcadaec6546d5cbe6.png

将一个新元素push栈将该元素添加到链的开头。所涉及的步骤与将字符插入链表列表缓冲区所需的步骤相同。 首先分配一个新的单元格,然后输入数据,最后更新链接指针,使新单元格成为链中的第一个元素。 因此,如果将元素e2推到栈上,将得到以下配置:

eb1da138959563da2b0dc835894251dd.png

在链表表示中,pop操作包括删除链中的第一个单元格并返回存储在该列中的值。因此,来自上图所示的栈的pop操作返回e2并恢复栈的先前状态,如下所示:

aa3a7370a981097096028bfd92936e99.png

对链栈中的pop和push的分析

push

我们以一个最基本的数字栈为基础分析,下面是需要的一些接口内容:

class 

接下来看代码分析:

void 

老办法,图解push过程,假设此时我们的链栈如下:

022b32ea29884479e6c5fbc9aa555dc2.png

我们的目的是push(7),将7放入栈顶,也就是要这样的结果:

925df087c8fe7021cfa7686b89c6f033.png

下面解释整个过程:

1. 新建一个临时节点,并用创建临时指针指向该节点,接着向该节点写入数字7,就像这样:

4560225d3737afd4359ab2585aa4d680.png

2. 然后,将头指针data里面的指针值,赋值给新节点的link字段,以便新节点可以连接到8这个节点:

367f7845bc69ff0fbfd39ec79e4473a0.png

3. 将temp里面的值,赋值给首指针data处。将data的指向正确改变:

645e37bb3bf862fe531eed37ac7b964b.png

4. 函数返回,得出正确的push后的结构:

6fbd01e0b545c201925bcd60c3b65e1b.png

pop

先看代码:

int 

图解过程如下: 1. 先将要pop出去的值进行保存

3f730b2d960126c0d21f08ba878b0227.png

2. 我们这边创建一个临时的指针变量Temp,然后将其指向首指针data指向的节点(即栈顶元素),就像这样:

a678eb8cd9a6c6b32aa4512d4d34dbe3.png

3. 然后改变首指针(即栈顶)的指向:

f6c34ccb311eeabbe98819c625094558.png

4. 最后删除temp指向的节点

2fb8ca83b3b28fa6c626c723ced3c26f.png

5. 此时函数返回。

注意,我们第二步不可以直接改变指针的指向而不使用临时节点,因为直接改变指针的指向会像下图一样:

228a218f6903cc2ce9701681acc9d3e3.png

这显然不是我们希望看到的。

链队列

队列类也使用链表结构进行简单的表示。为了说明基本的方法,队列的元素存储在从队列头部开始并以尾部结尾的列表中。并且为了保证入队和出队正确运行,Queue对象必须含有指向队列两端的指针。 因此,私有实例变量的定义在queuepriv.h的修改版本如下:

/*

那么为什么我们要设置一个尾指针呢? 首先我们假设一下我们初始化的队列如下所示:

0b372a784e2081e2bdb46801ce560e51.png

这个时候我们执行后入队操作:

b30afe398a4d04d0695b2a88bf128282.png

显然,这个时候我们相当于在链表中插入一个元素,且位于头结点的第一个,自然我们的复杂度为O(1)。但是当我们执行出队操作时,情况就不同了,我们必须验证头指针遍历到最后一个节点,再执行delet操作,此时算法复杂度为O(N)。

入队(enqueue)

那么是否有更好的办法呢?因此我们考虑一下添加一个尾指针(因为队列多数在链表的两端操作)。所以我们看下面一段代码:

void 

图解代码执行过程: 1. 假设我们初始的队列值为123,并且我们添加的尾指针指向的是我们的3的节点,如图:

3b466ac037bc177a3d3976177e68c074.png

2. 此时我们在队列尾部(3),这里加入数值4,此时,我们的操作应该是,建立一个指针,指向新建立的节点,然后往这个新节点写入数值:

c01b33d743a0be484f4ee8b9036e1d33.png

3. 接下来我们改变指针的指向,也就是将cp的内容复制到3下面的link字段(也就是tail指向的节点的link字段)。此时情况如下(分两步):

0cedf8d63ebbf584b9bc7d20e2960271.png

747001cf3377c58ad965121e68160fc7.png

4. 最终我们返回我们的队列就可以了,因此复杂度为O(1)

e905005ab6de5c054d86cd4e4074d5cc.png

出队(dequeue)

我们就拿上面完成的例子为例,进行我们的dequeue操作,我们先看2 3行代码,建立一个临时节点,指向与我们的head指针的指向相同,如下: 首先假设我们有完整的队列

4adf40f25076c7417d43157fb92eca6d.png

现在我们要进行的queue操作,于是将队头移除,以达到下图的结果:

5cd4bea224afa492f70f7395f6dd5989.png

同理,看代码:

int 
  1. 我们先将此时队头指向的数字给存储起来,然后新建一个指针,跟队头指针一同指向首元素1.

9371ead4d9190c08df22040908a82c09.png
  1. 然后改变头指针的指向

04e6e00d66fff8272080ed5064d6e28a.png
  1. 释放被dequeue掉的那个节点

35a9726dc298f7bc3dcb42ccb96de51d.png

算法复杂度分析

6b37b9d0b01ab0b55dad5c892206f0a8.png
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值