【算法与数据结构复习】| 队列和栈-01

        今天跟着左程云算法课013和014,复习了【队列和栈(以及循环队列)的实现】以及【栈和队列的相互实现】。是队列和栈复习的前半部分。

一、队列和栈的实现

        队列和栈逻辑结构,在代码实现时,其存储结构可以用链表也可以用数组。那么分别用链表和数组来实现队列和栈的类。队列是先进先出(offer和poll),栈是先进后出(push和pop),只需在写数据增加和删除时抓住这个特征即可,代码实现还是比较简单的。

(1)用链表实现队列

        用Java内部的双向链表LinkedList来实现队列,并且写代码的时候看了一下LinkedList的add和offer方法的区别。区别在于,在往队列中添加数据时,遇到队列大小限制时,add会抛出一个异常,offer会返回一个false,用add和offer都可以,这里使用offer。代码实现如下:

//用链表实现队列
	public static class Queue1{
		
		//用Java内部的双向链表来实现
		public Queue<Integer> queue=new LinkedList<>();
		
		//判断队列是否为空
		public boolean isEmpty() {
			return queue.isEmpty();
		}
		
		//向队列中加入num
		public void Addnum(int n) {
			//遇到队列大小限制时,add会抛出一个异常,offer会返回一个false
			//queue.add(n);
			queue.offer(n);
			
		}
		
		//从队列头拿数据
		public int poll() {
			return queue.poll();
		}
		
		//返回队列头的元素但是不弹出
		public int getnum() {
			return queue.peek();
		}
		
		//返回目前队列里有几个数
		public int size() {
			return queue.size();
		}
		
	}
(2)用数组实现队列

        左神在视频课里提到的,虽然用链表和数组实现的时间复杂度一样,他们的基本操作都是O(1),但是常数时间不一样,链表比数组要慢,这个想一下就知道。一般的笔面试要考的话也是用数组会比较多。用数组实现队列时,要设置两个变量head和end,分别指向队列的头和尾,所表示的是一个左闭右开的范围,这个队列中的数据是[head,end)。如果数据入队,那么把数据放到arr[end],然后end++;如果数据出队,那么返回arr[head]的数据,然后head++。比较简单,代码实现如下:

//用数组实现队列
	public static class Queue2{
		public int[] queue;
		public int head;
		public int end;
		
		//构造函数
		public Queue2(int n) {
			this.queue=new int[n];
			head=0;
			end=0;
		}
		//判断队列是否为空
		public boolean isEmpty() {
			return head==end;
		}
		
		//判断队列是否已满
		public boolean isFull() {
			return end==queue.length;
		}
		
		//往队列中加入元素
		public void Addnum(int n) {
			if(isFull()) {
				System.out.println("队列已满");
				return;
			}
			else {
				queue[end++]=n;
			}
		}
		
		//取队列头的元素
		public int poll() {
			if(isEmpty()) {
				System.out.println("队列为空,取数失败");
				return -1;
			}
			else {
				return queue[head++];
			}
		}
		
		//取队列头的元素,但不出队
		public int gethead() {
			if(isEmpty()) {
				System.out.println("队列为空,取数失败");
				return -1;
			}
			else {
				return queue[head];
			}
		}
		
		//取队列尾的数据
		public int getend() {
			if(isEmpty()) {
				System.out.println("队列为空,取数失败");
				return -1;
			}
			else {
				return queue[end-1];
			}
		}
		//返回队列数据长度
		public int getSize() {
			return end-head;
		}
		
	}
(3)用链表实现栈

        可以用Java内部的Stack来实现,这是java的模板方法(template method),本质上是一个动态数组。那这里直接用Stack模板来实现,那就非常简单了,代码如下:

//用java内部的动态数组实现栈
	public static class Stack1{
		public Stack<Integer> s=new Stack<>();
		
		//判断栈是否为空
		public boolean isEmpty() {
			return s.isEmpty();
		}
		
		//数据入栈
		public void push(int n) {
			s.push(n);
		}
		
		//数据出栈
		public int pop() {

				return s.pop();
		}
		//返回栈顶的值但不弹出
		public int peek() {

				return s.peek();
		}
		//返回栈的元素个数
		public int size() {
			return s.size();
		}
	}
(4)用数组实现栈

        用数组实现栈也是比较简单,只用设置一个变量size来指向栈顶就可以,表达的数据范围是[0,size),也就是说栈顶的元素是arr[size-1]。直接实现,代码如下:

	public static class Stack2{
		
		public int[] arr;
		public int size;
		
		public Stack2(int n){
			arr=new int[n];
			size=0;
		}
		//判断为空
		public boolean isEmpty() {
			return size==0;
		}
		
		//判断为满
		public boolean isFull() {
			return size==arr.length;
		}
		//数据入栈
		public void push(int n) {
			//先判断为满,懒得写,省略
			arr[size++]=n;
		}
		//数据出栈
		public int pop() {
			//先判断是否为空,懒得写,省略
			return arr[--size];
		}
		//返回栈顶数据但不出栈
		public int getnum() {
			//先判断是否为空,省略
			return arr[size-1];
		}
		//返回栈的元素个数
		public int size() {
			return size;
		}
	}

二、设计循环队列

力扣题目和测试链接:. - 力扣(LeetCode). - 备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。icon-default.png?t=N7T8https://leetcode.cn/problems/design-circular-queue/

        循环队列就是当数据入队入到数组最大限制之后,可以折回去继续使用数组前面已经被释放的空间。本科上数据结构课程的时候,老师好像讲了循环队列的实现,用的是取模的方法,比较复杂一些。左神的课里直接设置head、end、size还有limit,对于这个队列是否为空和是否为满的判断仅用size和limit来判断(limit其实就是arr.length,也可以不用设置limit,在判断的时候直接用arr.length就OK,这里为了方便设置了limit)。

        那么这样一来,关键的点在于:数据入队的时候,判断end的位置,如果end已经在limit-1的位置,把数据放在arr[end],end折返到0,否则就正常的end+1;数据出队的时候,判断head的位置,如果head已经在limit-1的位置,head折返到0,否则head+1;想清楚这个点就很好实现了,代码如下:

	public static class MyCircularQueue{
		public int[] arr;
		public int head;
		public int end;
		public int size;
		public int limit;
		
		public MyCircularQueue(int k) {
			arr=new int[k];
			head=0;
			end=0;
			size=0;
			limit=k;
			
		}
		
		public boolean isEmpty() {
			return size==0;
		}
		
		public boolean isFull() {
			return size==limit;
		}
		
		public boolean enQueue(int value) {
			if(isFull()) {
				return false;
			}
			else {
				arr[end++]=value;
				end= end==limit?0:end;
				size++;
				return true;
			}
		}
		
		public boolean deQueue() {
			if(isEmpty()) {
				return false;
			}
			else {
				head= head==limit-1?0:head+1;
				size--;
				return true;
			}
		}
		
		public int Front() {
			if(isEmpty()) {
				return -1;
			}
			else {
				return arr[head];
			}
		}
		
		public int Rear() {
			if(isEmpty()) {
				return -1;
			}
			else {
				int last= end==0?limit-1:end-1;
				return arr[last];
			}
		}
	}

三、队列和栈的互相实现

(1)用栈实现队列

力扣题目和测试链接:. - 力扣(LeetCode). - 备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。icon-default.png?t=N7T8https://leetcode.cn/problems/implement-queue-using-stacks/

        要用两个栈实现队列,用两个栈可以倒数据,数据进到in栈里,然后再倒到out栈里,这样数据一倒就能变成队列的正常顺序。只是倒数据的时候要注意两点:1)当out栈为空的时候才能从in里倒数据出来;2)如果倒数据,in里面的数据一定要倒完。

        核心是倒数据的操作,那么在实现队列的push,pop以及peek操作时,push只涉及到往in栈里加数据,在push函数中可以不去倒数据;而pop和peek是对out栈进行操作的,在进行取数据的操作之前要倒数据。想清楚这个就很好实现了,代码如下:

	//用两个栈实现队列
	public class MyQueue{
		public Stack<Integer> in;
		public Stack<Integer> out;
		
		public MyQueue() {
			in=new Stack<>();
			out=new Stack<>();
		}
		
		//倒数据
		//out为空的时候才能倒数据
		//in必须倒完
		public void InToOut() {
			if(out.isEmpty()) {
				while(!in.isEmpty()) {
					out.push(in.pop());
				}
			}
			
		}
		
		//队列加入数据
		public void offer(int n) {
			in.push(n);
		}
		
		//数据出队
		public int poll() {
			InToOut();
			int num=out.pop();
			return num;
		}
		
		//返回队头数据
		public int peek() {
			InToOut();
			return out.peek();
		}
		
		//判断队列是否为空
		public boolean isEmpty() {
			return in.isEmpty()&&out.isEmpty();
		}
		
	}
(2)用队列实现栈

力扣题目和测试链接:. - 力扣(LeetCode). - 备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。icon-default.png?t=N7T8https://leetcode.cn/problems/implement-stack-using-queues/

        用队列实现栈的核心思想在于:当数据入栈(push)时,计算一下入栈前的元素个数n,那么在本次数据入栈后,在进行n次将数据出队再入队的操作。也就数据入栈(push)时比较特殊,需要思考一下,其他操作都正常进行。

        另外在这里再强调一下,Stack有java模板函数,但是Queue没有。因此在创建的时候要注意下,Queue要用LinkedList(也就是双向链表)来实现。

public Stack<Integer> stack=new Satck<Integer>();
public Queue<Integer> queue=new LinkedList<Integer>();

用队列实现栈的代码如下:

	public class MySatck{
		public Queue<Integer> stack;
		
		public MySatck() {
			stack=new LinkedList<>();
		}
		
		//入栈功能
		public void push(int x) {
			//入栈之前先算一下队列中有几个数
			int num=stack.size();
			stack.offer(x);
			for(int i=0;i<num;i++) {
				stack.offer(stack.poll());
			}
		}
		//出栈功能
		public int pop() {
			return stack.poll();
		}
		
		//返回栈上面的数但不弹出
		public int peek() {
			return stack.peek();
		}
		
		
		//判断是否为空
		public boolean isEmpty() {
			return stack.isEmpty();
		}
		
	}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值