呔!“栈”住,队列!

简介: 呔!“栈”住,队列!

大家好呀,我是不会写开场白的帅蛋。


今天直入重点,玩儿栈和队列,英文名 Stack and Queue,线性数据结构的典型代表,数组和链表的兄弟姐妹。


下面,让我们来看看,它们是有多简单。

640.png



 



栈是一种后进先出(Last in First Out)的数据结构,简称 LIFO


啥叫后进先出呢?这就和打飞机,呃,打手枪一样,弹夹中最先插进去的子弹最后才打出去,越晚摁进去的子弹越早打出来。


别小看它,栈是一种很重要的编程概念,它在软件应用中很常见。我们每天都用到的浏览器就用到了,浏览器的“后退”按钮。


640.png


比如臭宝上班的时候正在浏览器上看@编程文青李狗蛋的技术文,此时弹出一个保持男性持久的框框,“不小心”点到了,正看的入迷的时候你的老大路过,此时拿出单身 N 年的手速点击后退,你老大一看你在看帅蛋的文章,赞赏你是积极上进的员工,奖励手纸一卷。


看,“后退”是多么的有用~

640.jpg

栈的定义



那么,到底怎么定义栈呢?


很简单。


栈是限制仅在表的一端(表尾)进行操作(插入和删除)的线性表。


表尾又叫栈顶(Top),允许插入和删除,那么另一端就叫做栈底(Bottom),啥也不能干,只能干等着第一个进栈的过来躺着。

640.png

栈的插入操作,叫做入栈(push)。存入栈的元素之间没有任何具体的关系,只有到来的时间的先后顺序。


入栈操作涉及的单个数据的进入,所以时间复杂度为 O(1),同时入栈过程中只需要单个的临时存储空间,所以空间复杂度为 O(1)。


640.png


栈的删除操作,叫做出栈(pop)。删完了,也就是栈底就是栈顶的时候,就叫空栈


同理,出栈操作涉及个别数据的出去且出栈过程只需要单个的临时存储空间,所以时间复杂度和空间复杂度都为 O(1)。

640.png


存入栈的元素之间没有任何具体关系,只有到来的时间的先后顺序.在这里没有元素的位置、元素的前后顺序等概念。


栈的存储结构


在上面说过,栈是线性表,那么它同样有顺序存储和链式存储


顺序存储


顺序存储的栈叫做顺序栈


顺序栈使用数组实现,下标为 0 的一端作为栈底,使用 top 做为栈顶,它来指示当前栈顶元素的位置,默认 top = -1 时为空栈。

640.png


链式存储


链式存储的栈叫做链栈


链栈用单链表实现,一般尾节点为栈底,使用头指针指向的节点作为栈顶,不需要头节点。top = NULL 为空栈。

640.png


啥同时因为顺序和链式本身的存储特点,顺序栈的元素个数是固定值,存在栈满的情况,而链式栈则不存在栈满的情况,除非内存被塞的满满的。


   队列



队列是一种先进先出(First in First Out)的数据结构,简称 FIFO


啥叫先进先出呢?这就和排队上厕所,谁先到谁先嘘嘘,到的晚的只能忍住。


同比栈,队列在软件应用中也很常见,就像现在我在一个字母一个字母的敲,最后输出在屏幕上你看到的一个个的字,这些就是最常见的队列的应用。


队列的定义


类比栈,怎么定义队列呢?


队列是限制仅在一端进行插入操作,在另一端进行删除操作的线性表。


允许插入的一端叫做队头,允许删除的一端叫做队尾队列的插入叫做入队列队列的删除叫做出队列

640.png



队列的存储结构


同为线性表,队列也有链式存储和顺序存储


链式存储


链式存储的队列叫做链队列


其实这就是单链表,而且是带头节点的单链表,这样的话对于入队或者出队来说,它们的时间复杂度与单链表的插入和删除的时间复杂度都是一样的,都是 O(1)。


在此,头节点指向队头,用 head 指向头节点,tail 指向队尾。


640.png

当 head  和 tail 都指向头节点时,为空队列

640.png


顺序存储


顺序存储的队列用数组实现。数组下标为 0 的一端为队头,用 head 指向,队尾用 tail 指向。


假设队列能存 5 个元素,当 head = tail,队列为空队列

640.png

从上图的空栈中,A B C 依次入队

640.png


执行三次入队操作,此时head = 0,tail = 3。可以看出,当入队列的时候,数据直接按序存储到数组中,时间复杂度为 O(1)。


如果此时要执行两次出队操作。

640.png



执行两次出队操作,相当于删除了 A B,此时 head = 2,tail = 3。从这可以看出,出栈的时间复杂度也是 O(1)。


是不是现在想说一句:就这?


还真不是就这。此时我再入两次队列。

640.png


这个时候问题来了,我就大小为 5,数组最后一个元素已经被占了,此时再入栈的话,就数组越界了,但是我这个队列明明没满,我下标是 0 和 1 的位置还空着,这咋整?

640.jpg

不慌,两种办法。


第 1 种,满了就向前跑

640.png


每次当 tail = n 的时候,所有的元素搬到 0 ~ (tail-head)的位置,这个时候入队的时间复杂度是 O(1) 或者 O(n),出队的时间复杂度也是 O(1)。


出队这个时间复杂度好理解,主要是入队为啥是 O(1) 或者 O(n)估计有点难理解。


可以这么来想,对于为 n 的数组,对于 tail 指向下标为 0 ~ (n-1) 的来说,入栈的时间复杂度都是 O(1),唯一不一样的是,当 tail = n 的时候数值需要向前跑,对于此时这步动作来说,时间复杂度为 O(n)。


跑动的这一步的 O(n) 可以均摊到 0 ~ (n-1) ,那么对于入队来说,平均时间复杂度就是 O(1)。


第 2 种,满了从头再来


怎么从头再来呢?


当队列满了,那就是 tail = n,前面如果有空,那 tail = 0 不就又能再来啦。


怎么让 tail = n 了以后再编程 tail = 0,那不就是首尾相连,循环队列就这么闪亮登场了。

640.jpg


循环队列


循环队列,就是队列的队头和队尾相接的顺序存储结构


如果是循环队列的话,那当队列满了 tail 不需要等于 n ,直接指向了下标为 0 的位置。

640.png

如果此时要执行入队操作,那就会变成:

640.png

如果想更直观一些,我可以把它掰弯了给大家看。

640.png


你仔细看上面那张图,你会发现一个问题,如果再入队一个元素的话,队列满了,此时 tail = head。

640.png

那问题来了,队列空的时候 tail = head,现在队列满了,也是 tail = head,我傻了呀,我怎么知道现在的队列是啥状态呢?


那只能有一者做出牺牲了,空队列啥也没有,显然和个废物没啥两样,所以只能满队列做牺牲,牺牲一个位置啥也不放,也就是 tail 和 head 相差为 1 的时候就队列满了。也就是下面这种。

image.png


因为 tail 可能比 head 大(正常占用完)也可能比 head 小(做了循环),所以判断队列满的条件就成了 (tail + 1) % n = head


栈和队列到这就讲完啦,哎呀妈呀画了这么多图可累死我了,虽然丑丑的...

640.jpg


再往下面搞就是栈和队列的实战了,敬请期待我的不定时上线。


看到这的都是真爱,点赞在看留言么么哒给我刷起来~


我是蛋蛋,我们下次见!





相关文章
|
20天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
102 9
|
11天前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
19 1
|
13天前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
16天前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
18天前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
46 4
|
23天前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
1月前
数据结构(栈与列队)
数据结构(栈与列队)
20 1
|
1月前
|
存储 JavaScript 前端开发
为什么基础数据类型存放在栈中,而引用数据类型存放在堆中?
为什么基础数据类型存放在栈中,而引用数据类型存放在堆中?
71 1
|
1月前
【数据结构】-- 栈和队列
【数据结构】-- 栈和队列
17 0
|
1月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
31 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器

热门文章

最新文章