数据结构:栈和队列

一.栈和队列

1.1什么是线性表

一次保存单个同类型元素,多个元素之间逻辑上连续
数组,链表,栈,队列,字符串(内部就是字符数组char[])

1.2什么是栈和队列

栈和队列其实是操作受限的线性表。
之前的数组也罢,链表也罢,既可以在数组的头部插入和删除,也可以在数组的尾部插入和删除,甚至在任意位置都可以插入和删除。
栈和队列只能在一端插入元素,和删除元素
栈:水杯
1.只能从一端插入元素,也只能从这一端取出元素(栈顶)
将12345依次添加到栈中
在这里插入图片描述
我们发现最先添加的元素就在当前栈的最低端,最后添加的元素就在栈的最顶端。
添加元素只能从栈顶添加,取出元素只能从栈顶取出
取出栈中元素
在这里插入图片描述
在这里插入图片描述
从栈中添加元素和从栈中取出元素恰好相反,最后添加的元素最先取出->Last In First Out(LIFO)
栈的特点:先进后出,后进先出的线性表

添加元素和删除元素的一端称为栈顶,另一端称为栈底

1.3栈在现实生活中的应用

栈在现实生活中的应用(无处不在的栈的应用)
1.无处不在的undo(撤销)操作,从栈顶弹出这个错误的元素,然后文本编辑器就会取出当前的栈顶元素。
在任何一个编辑器中输错了一个内容使用ctrl + z就返回到了上一次输入的内容
在任何一个浏览器点击在这里插入图片描述
就能返回上一次浏览的网页
2.操作系统栈:
程序在执行过程中,从A函数调用B函数,从B函数调用C函数,返回执行时如何得知从哪继续执行,其实背后就是栈这个结构。funA(){
print();//1
int a = 10//2
funB();//3
hello world;//4
}
funB(){
int a = 10;//1
fun c();//2
helloworld;//3
}
funC(){
int a = 10;//1
helloworld;//2
}
在这里插入图片描述

1.4栈的实现

栈的三个核心操作:push(E e):向栈中添加元素-入栈或者压栈操作
E pop():出栈操作,弹出栈顶元素
E peek():查看栈顶元素,但不出栈
a.基于数组实现的栈-顺序栈
栈是一个只能在栈顶插入元素,在栈顶删除元素的结构

数组末尾插入和删除元素,数组末尾就是此时的栈顶
在这里插入图片描述
->在这里插入图片描述

b.基于链表实现的栈-链式栈

二.队列

2.1什么是队列

队列:FIFO,先进先出的数据结构,元素从队尾添加到队列中,元素只能从队首出队列

2.2队列的核心操作

push,offer(E val):将元素入队
peek():查看队首元素
pop,poll():弹出队首元素

元素的出队顺序和入队顺序保持一致
1 2 3 4 5
在这里插入图片描述
在这里插入图片描述

队列现实生活中的应用:
现实生活中,各式各样的“排队”操作

2.3队列的使用

同样的队列也有基于数组实现的队列和基于链表实现的队列
出队操作只能从队列的头部进行,若采用数组的方案,每次出队一个元素,接得搬移剩下的所有元素,向前移动一个单位。
此时采用链表的方案更加适合队列的结构。
出队列:删除头节点
添加元素:在链表的尾部添加
数组实现的队列:顺序队列

链表实现的队列:链式队列

2.4用队列模拟实现栈

java.util.Queue
java.util.LinkedList
在这里插入图片描述

2.5循环队列

循环队列:操作系统的生产消费者模型,MySQL数据库的InnoDB存储引擎中的redo日志。

基本使用长度固定的数组来实现,数组在实现队列时,若数组头部删除元素,需要频繁地移动后面的元素,带来效率比较低。

出队和入队操作,使用两个引用,一个叫head,一个叫tail,添加元素在数组的尾部添加,删除元素只需要移动head引用指向的地址即可(逻辑删除)

循环队列就是使用长度固定的数组来实现,数组的头部就是队首(head),数组的尾部就是队尾(tail)。数组[head…tail)是循环队列的有效元素

head永远指向循环队列的第一个元素
tail永远指向循环队列有效元素的后一个位置
循环队列出队一个元素
所谓的循环队列指的就是当head或者tail引用走到数组末尾时,下一次再继续向后移动其实返回数组的头部继续操作。
循环队列再删除元素时,不需要进行数据的搬移。
当有新的元素在添加是就会覆盖掉之前的元素
长度为5的数组
在这里插入图片描述
数组为空,循环队列为空head = =tail
在这里插入图片描述
队列已满
在这里插入图片描述
我们此时数组为空和数组满head == tail,因此没法区分当前循环队列到底是空还是满。
1.因此我们在循环队列中,若tail + 1==head,就认为循环队列已满。在循环队列中浪费一个空间,判断当前队列是否已满。
若此时(tail + 1)% n == head;认为循环队列已满
2.head和tail的移动不能简单的直接+1,使用取模操作,取数组长度tail = (tail + 1)% n;
对数组长度取模的本质在于当head和tail走到数组最后一个索引位置时,下一次要返回数组头部,就必须使用+1对n取模
3.head = =tail认为队列为空

关于最后一个元素的索引取值
除了tail这个引用指向0这个位置以外,其他情况的最后一个位置索引 = tail-1
当tail==0时,最后一个元素就在数组的末尾,索引=data.length - 1在这里插入图片描述

在这里插入图片描述

2.6双端队列

双端队列:Deque->Queue的子接口
这个队列既可以从尾插,头出
也可以从头插,尾出
以后无论使用的是栈还是接口,统一使用双端队列接口
不推荐使用Stack这个类,这个类已经是时代的弃子,效率很低,都是同步操作。
双端队列的一个子类就是LinkedList。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值