队列的相关概念及操作

队列概念

什么是队列?队列就是一个队伍,队列和栈一样,由一段连续的存储空间组成,是一个具有自身特殊规则的数据结构,我们都知道栈的先进后出的规则,而队列刚好相反,是一个先进先出的(FIFO)或者说后进后出(LILO)的数据结构。

队列的是一种受限制的数据结构,插入操作只能从一端操作,这一端叫做队尾,而移除操作也只能从另一端操作,这一端叫队头。我们把插入和移除操作分别叫做入队和出队。

一般而言,队列的实现有两种方式,数组和链表,用数组实现队列有两种方式,一种是顺序队列,一种是循环队列。在顺序存储方式中,队列会有两个标记。

队列的相关操作

出队:

一开始两个标记都指向数组下标0的位置,分别为head(队头指针)和tail(队尾指针)。当一个元素入队后,tail指针会响应地加1;

入队:

当有一个元素进行出队操作,即这个元素从队头移除了,此时head指针会相应地往后移动一位,此时新队列的队头就是原来队列的第二个元素。

思考一个问题:当一个顺序队列进入若干个元素后,队列已经满了,不能再进行入队操作了,我们称之为“真上溢”,此时我对其中的一部分元素进行出队操作,那么队列此时已经不是满的状态了,但是我们仍然不能进行入队操作,这种状态我们称之为“假上溢”。那么如何解决假上溢的问题呢?这时就要用到存储的第二种方式,循环队列了。

当顺序队列出现假上溢的时候,其实队列前端还有空间,我们可以不用把标记指向数组外的地方,只需要把标记重新指向开始的地方就可以了。就是把这个数组首尾连接,成为一个圈,那么此时我们又能进行入队操作。这样就解决了“假上溢”的问题

其实,如果细心的同学还会发现一个问题,如果使用循环队列的方式,当队列为空以及队列满的时候,head和tail指针都是出于重叠的状态,这就会出现歧义了,这会让我们分辨不清当head和tail重叠的时候,队列是空的还是对满状态。一般情况,我们为了区分,一般在循环队列中规定队列的长度为所存储数组的长度减去1,即有一个位置不放元素。这样的话,当head==tail时,说明队列为空,当head == (tail +1)%length时,队列为满的状态

以上是队列的相关概念下面以代码的形式实现队列的相关操作:·


public class ArrayQueue {
	
		private Object[] items;
		private int head = 0;
		private int tail = 0;
		/**
		 * init the queue
		 * @param capacity: the length of queue
		 */
		public ArrayQueue(int capacity) {
			this.items = new Object[capacity];
		}
		/**
		 * put item into queue
		 * @param item
		 * @return
		 */
		public boolean put(Object item) {
			if(head == (tail+1) % items.length) {
				return false;
			}
			items[tail] = item;
			tail = (tail+1) % items.length;
			return true;
		}
		/**
		 * get the head element
		 * @param head
		 * @return
		 */
		public Object peek() {
			if(head == tail ) {
				return null;
			}
			return items[head];
			
		}
		/**
		 * poll a element
		 * @return
		 */
		public Object poll() {
			if(head == tail) {
				return null;
			}
			Object item = items[head];
			items[head] =null;
			head = (head+1) % items.length;
			return item;
		}
		/**
		 * isFull
		 * @return
		 */
		public boolean isFull() {
			return head == (tail +1) % items.length;
			
		}
		/**
		 * isEmpty
		 * @return
		 */
		public boolean isEmpty() {
			return head == tail;
		}
		/**
		 * get queue size
		 * @return
		 */
		public int size() {
			if(tail >= head) {
				return tail - head;
			}else {
				return tail + items.length -head;
			}
		}
		
		
	
	public static void main(String[] args) {
		ArrayQueue queue = new ArrayQueue(4);
		System.out.println(queue.put("A"));//true
		System.out.println(queue.put("B"));//true
		System.out.println(queue.put("C"));//true
		System.out.println(queue.put("D"));//false
		
		System.out.println(queue.isFull());//true
		System.err.println(queue.size());//3
		System.out.println(queue.peek());//A
		System.out.println(queue.poll());//A
		System.out.println(queue.poll());//B
		System.out.println(queue.poll());//C
		
		System.out.println(queue.isEmpty());//true
		
		
	}
	

}

队列的使用场景

在一般程序中,会将队列作为缓冲器或者解耦使用

例如手机在线秒杀用到的队列,前几年某米的饥饿营销,用户想要买一款中意的手机,得现在它的官网上预约,等到开抢的时间,疯狂地点击抢购的按钮,一般来说,每次提供的名额都是供不应求,加入名额只有2000,但是抢购的人有20000,服务器不可能直接处理两百万人的请求,那么真正的处理方法就是:在接受到每个请求后,把这些请求按顺序放在队列的队尾中,然后提示你“正在排队中”,而在队列的另一端,也就是队头,会有一些服务器在处理,根据先后顺序告知用户的抢购结果

还有一个重要的应用就是队列与生产者消费者设计模式的应用,在队列的队尾对接的是生产者,在队头对接的就是消费者。生产者把生产号的产品进行入队操作,在队头消费者去消费出队的产品。因此,对于生产者和消费者来说,有一点是非常重要的,那就是生产的速度和消费的水平要持平,如果生产得太快,而消费得太慢,那么队列就会很长,对于计算机来说,这样占用的空间就会很大。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值