栈和队列(一级)

栈和队列我们一般是放在一起来讲的,先讲栈,再讲队列,他们有什么共同点,栈和队列他们都是线性表,都是线性结构,但是他们

是操作受限制的线性表,比如我们举个列子来说,在我们的线性表里面,我们以单链表为例,我们可以把其中的任何一个删除,

可以删除第一个,也可以删除中间的一个,也可以删除最后的一个,添加的时候也是,你可以添加到任何两个元素中间,你也可以

加到最后,当然你也可以加到最前端,添加设删除操作位置受限吗,不受限,可以向任何位置添加和删除节点,但是我们的栈和队列就不是了,


栈是怎么回事?

栈Stack这对我们来说并不陌生,每次我们画创建内存分配图的时候,手动画一个栈内存,就是他的,栈又叫堆栈,这个堆不要理解成栈内存

和堆内存中的堆,他们是没有关系的,栈Stack又叫堆栈,它是运算受限的线性表,首先它是线性表,但是它是运算受限的,怎么受限啦,

只能在表的一端插入和删除操作,只能在一端,比如只能在头部做添加和删除操作,或在尾部做添加和删除操作,只能在一端进行,

不允许在其它位置坐插入和删除操作,查找也只能得到一端顶端的,那我们讲插入删除一端,我们就有一个栈顶,另外一端就叫做栈底,

一个叫栈顶,一个叫栈底,如果一个元素也没有我们就称之为空栈,对栈来说我们主要是做三个操作,实际上最主要的是两个,一个叫入栈,

什么叫入栈啊,就是做一个添加操作,什么叫出栈,出栈什么意思,就是做一个删除操作,还有一个就是获取栈顶元素,我要看看最上面的元素

到底是几,但是那个不删除,相当于查询,他这里面我们看这个图吧,刚开始这个栈呢还是一个逻辑结构,我们知道可以使用数组来实现,

也可以使用链表来实现,你看这个图是不是一个数组,只不过这个数组我们怎么放啊,我们向下放,我们不是左右放了,刚开始一个元素也没有,

是空的啊,刚开始是一个空栈,这就是一个数组,是不是一个元素也没有,那最下面的这块既是栈底也是栈顶,因为它一个元素也没有,

然后A入栈,栈顶就网上入了一个,栈底永远不变,我可以再加个B,再加个C,再加个D,你看栈顶元素哦,栈顶是不是一直在发生变化,

我把A,B,C加进来,我能不能把D加到C的下面去,在栈里面是不允许的,如果你想这么做也可以,你先把C拿出来,C的上面只能放D,

我想把D放到C的下面,那你必须先把C拿出来,多两个操作才可以,这三个操作叫什么,A入栈,出栈就需要从最上面的开始拿,先拿D,

才能拿C,不拿C你就不要打算拿D,栈顶一直在发生变化,栈底是一直没有变的,这就是我们所说的一个栈,这么做有什么意义吗,

当然有意义
我们先看生活中的案例,书怎么摞,是不是一本一本网上摞,拿的时候先拿最上面的,最上面有不要抽中间的,

有人说这不合理啊,我就想抽中间的,那他就不是栈,那他就是线性表,给我把中间的一本书给抽走了,是不是相当于做了一个

删除操作啊,而把中间一本书删除了,如果你允许这种操作的话那他就不是栈了,他就成了线性表了


包括这个冰糖葫芦,它是栈还是线性表呢,看你怎么吃了,做这个冰糖葫芦的时候基本上都是栈的,一个一个插进去的,吃的时候

不一定吗怎么吃,先吃中间的那个,一般我们先吃上面的,按照相反的顺序来吃,如果你考虑这一点的话,他就是一个栈,



这是一个酒杯塔,我们在某个宴会的时候都会看到这个,一般我们看到这个酒杯塔的时候,一般会看到一个场景,什么场景啊,

一个人一不小心把下面的碰倒了,结果整个酒杯塔就整个塌掉了,这是一个,有人说这怎么是栈,好好的想一下,这不是一个

简单的是或者不是能够说明白的,那就太简单了,大家首先想,他一共分几层,一共分4层,如果我们把各层是一个整体的话,

这四层之间,他应该是个栈,为什么啊,因为你堆这个酒杯塔的时候,先是第一层吧,再是第二层,再是第三层,再是第四层吧,

拿的时候呢,拿的时候就正好相反,先拿最上层的,对同一层来说,是有很多,那就不算是栈了,我们从大的层次来说它是一个

栈的结构,便于大家理解


实际上最容易理解的是这个,每次我们画创建对象时候的栈内存,每调用一个方法,调用main方法的时候,他是不是要开辟一块

空间,main方法里面调用show方法啦,他是不是要再开辟一块空间,show里面再调用一个方法,他就要再开辟一块空间,

这个空间该怎么办,是不是向上摞的,这一块我给大家画一下,我们开始调用方法了,首先我们有一个方法,在这里画了一个方法,

这个方法我们在这里标记一下,main方法,他调了一个方法show方法,这个方法叫show,mainf方法里面放局部变量,

main方法的局部变量,show里面是放show里面的局部变量,如果show方法又调用了一个方法,怎么办,比如取个名字,叫add,

然后又怎么了,大家看这个像不像一个入栈,出去的时候谁先出去,是不是add方法执行完了空间释放了,我之前的show方法的

数据还有吗,有,show在下面,都在下面保存着,当你add弹出的时候,show方法的数据是不是也可以操作了,show方法你能去操作main吗

show方法也调用完了,弹出了,是不是又回到main方法里面,等main方法也执行完了,栈变成空的了,这就是我们所说的栈



4个字来概括他,叫后进先出,记住他的特点,后进先出表,Last In First Out,栈是这样的一种结构.


那对于这个栈来说呢,大家重点记住3个词语,一个叫push,一个叫pop,一个叫peek,我们也不要记get,为什么要记这些,

push是谁,push就是入栈,我把你推进去,pop弹出,出栈,相当于删除操作,peek获取栈的元素,获取顶部元素,push入栈

pop出栈,peek获取栈顶元素,这是我们所说的一个栈,他的存储结构呢,同样,可以采用顺序结构比如数组,也可以怎么办,

也可以采用链式存储结构链栈,顺序栈和链栈,只不过说比我们的线性结构表要简单,为什么,因为限定位置了,

这个大家知道就可以了,存储结构可以采用数组,也可以采用链表,叫顺序栈和链栈,栈的话就记住这些基本的概念,
下面我们来看一下一个兄弟,这个兄弟叫队列.

什么叫队列呢?

每次打饭的时候是不是都要排队啊,先来后到吗,栈是先进后出的,队列是先进先出的,队列叫queue,简称队,

他同样是运算受限的线性表,他怎么受限制的,它是在表的一端插入,另外一端删除,插入的这一端我们叫做队尾,

排队的话你要排到最后面,能不能排到最前面,删除的这一端叫队首,特别容易理解吧,插入元素叫入队,删除元素叫出队,

他最大的优点就像我们吃饭排队,地铁排队一样,这就会变成先进先出,生活中这样的例子有没有啊,像超市的购物车,

你看排成了一个队列,推车子的时候不用的时候放在最后,使用的时候使用最前面的就可以了,包括我们排队的,地铁排队,

那先排队的是先进,后排队的要站到最后,这个没有什么任何的难度


生活案例,排队打饭,排队进地铁站,还有上地铁,都要排队


技术案例:多线程的时候我们CPU只有一个,那怎么办啊,那就排队,有什么就绪队列,有什么堵塞队列,到时候我们会给大家来讲,

这个大家要知道



对于队列来说我们主要是要掌握两个操作,一个叫入队,一个叫出队,注意两个单词,Queue队列是它,enqueue是入队,

dequeue这个单词是出队,记住这两个单词,peek好像刚用过,获取队首元素,这就是我们关于队列的相关内容,再看他的存储结构

顺序队列,第二个采用链式队列,还是这两种存储结构


方法1: 采用数组做存储结构,这个结构我们来看一下,我们把它理解为一个数组就可以了,初始状态是一个元素也没有,

front这是一个头指针,rear是尾指针,先加一个A,再加一个B,再加个C,再加个D,再加E,如果我再加个F,F要入队了,

当你把F写到这儿的话,这个指针就要变了,就要指向F了,指向他就可以了,我们再随便加一个Z,那么rear指针又成了6了,

这叫入队,现在front是0,然后出队,谁出队啊,A出去,A出去之后,front怎么办,front指向1了,B要是再出去,front就指向2了,

D要是再出去呢,front就指向3了,你有没有发现这个时候出了一个问题,出了什么问题,别忘了我们这个时候是一个数组,

我们现在画的是一个数组,结果到最后出现一个什么情况了,你的头是谁啊,结果导致前面的数组都变成空了,

这不是都浪费了吗,这时候我们该怎么办,如果单纯的采用数组来做的话,会存在这么一个问题,有人说那我有办法啊,

如果A一删,我就让B到A的位置,那这样效率最低了,那肯定是不合适的,有没有解决的办法啊,给大家一个思路,

如果采用普通的数组就会导致front之前的数据丢失了,浪费了,闲置了,怎么办,采用循环数组



方法2: 就是使用循环数组,就是收尾相连吗,实际上还是一个数组,只不过我们可以怎么来理解呢,rear如果满了之后呢,数组一共分了

5个空间,rear末尾已经到了最后一个元素了,如果再入队的话,可以入队到第一个,入到前面去,但是指针的变化需要做相关的

一个记录,在这里我提一下就可以了
对于链式队列来说呢,怎么办?

同样的他为了处理方便,他增加了一个头结点,如果你想按照他这个来做,我想入队该怎么办,入队你是不是要创建一个新的结点,

入队就是添加一个元素,它的往最后加,我要出队呢,出队是谁啊,目前这队列里出队谁出队,a0出队,那a0怎么就出队了,把它删了,

怎么就把它删了,front存的地址值就要执行a1了,这就是一个出队操作


栈和队列不是我们的一个重点,我们掌握它的相关的基本理论,在这里我们再讲一个双端队列,叫deck,


什么叫双端队列?

这是个前端,这是个后端,之前我们是怎么回事,这个是进的,这个是出的,现在变了,这一端既可以出也可以进,这一端既可以进也可以出,

双端队列,两端都可以进队和出队,这个大家记住了,底层这里还可以是数组,或者链表,这是一个,这是一个最完整的双向队列,

实际开发中可能还会有这样的一些需求,输出受限的双向队列,还有一个输入受限的双向队列,什么叫输出受限,这边可以进,这边也可以进

但是出的话只能这边出,是不是输出受限啊,还有一个输入受限,就是这一端可以出,这一端也可以出,但是进的话只能这一端进,

和我们规定的只有一端可以进,一端可以出,那就成我们普通的队列了,如果我们的双端队列,规定只能这边进,只能这边出,就成了栈了,

双端队列既可以做队列操作,也可以做栈操作的,只要有一端受限他就成了栈了,你为什么讲这个啊,JAVA里面就是这么来实现的,

基本的理论 讲到这里的话



现在来看JAVA里的栈和队列,Java里面的线性表有什么,有Vector,ArrayList,LinkedList,同样等我们学了栈和队列之后,

JAVA里面有哪些栈和队列呢,大家来看

1. Stack类: 一看这个单词就是栈,已经过时了,因为他的父类就是Vector,Vector过时了,他也就过时了,虽然他的名字

取得特别好,但是我们以后不用他

2. Queue: Java里面有这么一个类,Queue就是队列的,他就是队列类,如果我们想使用队列的话,这个类就可以了,但是Queue

是一个接口,他不是实现类

3. Dequeue: 还有一个叫双端队列,叫Dequeue,虽然叫双端队列,但是在JAVA里面我们一般把它当做什么来对待的,当做栈来进行

处理的,注意这都是两个接口,我们最终要实现栈操作,或者队列操作的话,是不是还得用他们的实现类,那他们的实现类是什么,

我们打开我们的代码看一下,public interface Deque<E> extends Queue<E> ,首先要明确它是一个接口,他的父接口是队列

Queue我们再来看队列,public interface Queue<E> extends Collection<E>,队列里面有哪些方法啊,一个入队和一个出队,

就这样的一些操作,我们在Deque里面增加哪些操作,在双端队列里面有哪些操作呢,又增加了相关的一些方法,E removeFirst();

删除第一个,E removeLast();删除最后一个,E getFirst();获取第一个,E getLast();获取最后一个,void addFirst(E e);

添加第一个void addLast(E e);添加最后一个,是不是两端都可以进行添加和删除操作,都是可以的,void push(E e);

这里还有一个push,push是入栈,pop是出栈,peek获取栈顶元素,这两个都是接口,问他们的实现类是什么,

他们的实现类在这里看还不好看,看API呗,

Queue是队列,已知的子接口,子接口Deque,他有什么实现类,有两个,一个叫LinkedList,也就是LinkedList既可以做栈来用,

也可以做队列来用,还可以做线性表来用,LinkedList其实是非常特殊的实现类,他既可以做栈来用,也可以做队列来用,

还可以做线性表来用,都是可以的,既然是Linked,那当然是链表结构,这里还有一个ArrayDeque,从名字上来看,他是一个什么?

他就是一个数组的结构,这个用的不多,如果你想采用数组结构的栈,或者队列的话,请用这一个,就可以了,用它就行了,

这就是我们讲的相关的内容,Java里面实现队列用Queue,实现栈的话就用Deque就可以了,但是他们有一个共同的实现类,

我们用LinkedList,当然ArrayDeque就很少用了,底层采用的是数组结构的,LinkedList采用的是链表结构的,

记住我这个结论,下面我们领着大家做一个例子
package com.learn.stackqueue;

import java.util.Deque;
import java.util.LinkedList;

/**
 * 将10进制转化为2进制
 * 首先这个规则大家知道吗
 * 10进制变二进制怎么变大家知道吗
 * 比如我这里又一个数13,把它变成二进制
 * 13除以2,商是2,余数是1,拿着6再除以2
 * 商是3,拿着3再做被除数,余数是1
 * 再除以2商是0,余数是1,倒着来
 * 我们要实现这个操作,跟什么有关系,肯定是用循环
 * 其实这是一个链式循环的经典案例,
 * 链式循环的时候可以做一下这个,循环条件是什么,商等于0
 * 循环操作是什么,循环操作是除以2,
 * 有人说我不觉得这和栈有什么关系,这个和栈又关系吗?
 * 我们先把栈放到一边,先复习一下while循环
 * 循环语句看大家做的怎么样了
 * 
 * 那栈和队列的内容就讲到这里了,
 * @author Leon.Sun
 *
 */
public class TestConvert {
	
	public static void main(String[] args) {
		
		/**
		 * 第一步给定一个十进制数
		 * 13做被除数的,n最后没有变
		 * 我们还得输出n
		 * 如果是31呢,因为再加个1就是2的5次方了
		 */
		// int n = 13;
		// int n = 31;
		
		/**
		 * 15应该是4个1吧
		 */
		// int n = 15;
		
		/**
		 * 有人说我也不知道结果对不对,我们可以使用计算器
		 * 查看----程序员
		 */
		int n = 100;
		
		/**
		 * 把十进制转换为二进制
		 * 我们定义一个变量被除数
		 * t代表被除数,t等于n
		 * 为什么要把它作为t,因为t被除数一直在发生变化
		 * 
		 */
		int t = n;
		
		/**
		 * 给个String,刚开始是个空的,
		 * 这里就不用这个String了,
		 */
		// String str = "";
		
		/**
		 * 定义一个空栈
		 * 怎么定义,创建一个对象呗
		 * Deque是接口啊,使用LinkedList就可以了
		 * 创建了一个空栈
		 */
		Deque stack = new LinkedList();				
		
		/**
		 * 循环第一步干什么
		 */
		do {
			
			/**
			 * 第一步是求余数,除以2求余数,
			 * 相当于我们刚刚做了什么操作,
			 * 13除以2得到1了,
			 * t对2取余数,
			 */
			int mod = t%2;
			
			/**
			 * 我们要把它拼接起来
			 */
			// str = str + mod;
			
			/**
			 * 我往前面加总可以了吧
			 */
			// str = mod + str;
			
			/**
			 * 然后下面输出这个余数呗
			 * 输出一下这个mod
			 * 这个到时候我们会完善的
			 * 这里不是输出余数,而是入栈
			 * 没得到一个余数需要入栈
			 * 怎么入栈,入栈是哪个单词push
			 * 让余数进去,循环的过程中要入栈
			 */
			// System.out.println(mod);
			stack.push(mod);
			
			/**
			 * 6是商,然后拿到商再做被除数
			 * 我们把步骤写的细一些,
			 * result变成6了,下一次是被除数
			 */
			// int result = t / 2;
			
			/**
			 * 使用商做被除数
			 * 先把这个思路写对了
			 * 思路写对了那我们就可以做了
			 * 把result赋给t
			 * 这两步可以合成一步
			 */
			// t = result;
			t = t / 2;
			
			/**
			 * 条件是什么意思
			 * 当我们的商大于0
			 * 条件是t大于0
			 * t大于0就行了
			 * 但是写到这里好像和栈队列没有一点关系
			 * 我们先输出一下看结果怎么样 1011
			 * 这个1011是什么,是不是我们刚才得到的1011这个结果
			 * 但是我们需要的结果不是1011,是需要倒着来,是1101,
			 * 那该怎么办,并且大家想一下,有没有办法,有,我想了一个办法
			 */
		}while(t>0);
		
		/**
		 * 输出结果
		 * 再加上一个str,但是这里还是1011,
		 * 这不对,你看就这么得到了,注意到目前为止
		 * 练习的只是循环,有一个小技巧,str往前面加,不要往后面加就可以了
		 * 但是我有这么一种思想,我把栈用一下,我这里画上一个栈,
		 * 大家来看,我们第一次得到的余数是几,是1,我把1写到这儿,
		 * 第二次我们得到的是0,把0写到这儿,第三次得到的是1,
		 * 第四次得到的也是1,你看是不是按照这个顺序,出去的时候怎么办,
		 * 正好相反,是不是正好相反,出去的时候变成1101,是不是就得到我们的结果了
		 * 我们按照这个思路来实现一下,该怎么办,这个ln也不要
		 */
		System.out.print(n + "------->");
		
		/**
		 * 输出的时候是不是需要出栈了
		 * 怎么出栈,估计得用循环了
		 * 条件应该是什么啊,当栈非空就可以了
		 * 我怎么知道他非空啊,不要紧人家都给你写好了
		 * isEmpty是否是空的
		 */
		while(!stack.isEmpty()) {
			/**
			 * 不太对,ln不要了
			 */
			System.out.print(stack.pop());
		}
		
	}	
}
这个例子大家都做过,借助栈实现进制转换


通过栈和队列我们学好什么?

什么是栈什么是队列?

1. 栈和队列首先都是线性表,他们都是线性结构,但是他们是操作受限制的线性表,什么操作受限制了,一个删除,一个添加

2. 栈是怎么回事,一端入栈和出栈,队列是一端入队一端出队

3. 栈有一个特点,后进先出,队列有一个特点,先进先出

4. 另外我们还有一个双端队列,这个大家要知道,JAVA里面是有这个实现的

5. JAVA里面有哪些栈和队列大家要知道,双端队列他的名字叫队列,但是实际开发中我们把它当做栈来用的,我们现在在他的一端

来插入和删除,他就成了栈,

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值