漫画算法-学习笔记(05)

漫画算法-小灰的算法之旅(5)

1. 什么是队列

队列(queue)是一种线性数据结构,它的特征和行驶车辆的单行隧道很相似。不同于栈的先进后出,队列中的元素只能先入先出(First In First Out ,简称FIFO)。队列的出口端叫作队头(front),队列的入口端叫作队尾(rear)

与栈类似,队列这种数据结构既可以用数组来实现,也可以用链表来实现。

用数组实现队列时,为了入队操作的方便,把队尾位置规定为最后入队元素的下一个位置

和栈操作相对应,队列的最基本操作是入队和出队列。

2. 队列的基本操作

对于链表实现方式,队列的入队列和出队列操作和栈是大同小异的。但是对于数组实现方式来说,队列的入队列和出队列操作有些变化。

入队列

入队(enqueue):就是把新元素放入队列中,只允许在队尾的位置放入元素,新元素的下一个位置将会成为新的队尾。

出队列

出队列(dequeue):就是把元素移出队列,只允许在队头一侧移出元素,出队元素的后一个元素将会成为新的队头。

3. 代码实现

用数组实现的队列可以采用循环队列的方式来维持队列容量的恒定。

什么是循环队列?

假设一个队列经过反复的入队和出队操作之后,还剩下2个元素,在"物理"上分布于数组的尾部位置。这时又有一个新元素将要入队。

在数组不做扩容的前提下,如何让新元素入队并确定新的队尾位置呢?我们可以利用已出队元素留下的空间,让队尾指针重新指回数组的首位。

这样一来,整个队列的元素就“循环”起来了。在物理存储上,队尾的位置也可以在队头之前。当再有元素入队时,将其放入到数组的首位,队尾指针继续后移即可。

一直到**(队尾下标+1)%数组长度=队头下标**时,代表此队列真的已经满了,需要注意的是,队尾指针指向的位置永远空出一位,所以队列最大容量比数组长度小1。

数组实现循环队列代码
private int[] array;
private int front;  //队头
private int rear;   //队尾

public MyQueue(int capacity){
  this.array=new int[capacity];
}

/** 
* 入队
* param element  入队的元素
*/

public void enQueue(int element) throws Exception{
  if((rear+1)%array.length ==front){
    throw new Exception("队列已满")}
  array[rear]=element;
  rear =(rear+1)%array.length;
}

/**
* 出队
*/
public int deQueue() throws Exception{
  if(rear==front){
    throw new Exception("队列已空");
  }
  int deQueueElement =array[front];
  front=(front+1)%array.length;
  return deQueueElement;
}

/**
* 输出队列
*/
public void output(){
  for(int i=front;i!=rear;i=(i+1)%array.length){
    System.out.println(array[i]);
  }
}


public static void main(Strings[] args) throws Exception{
  
  MyQueue myQueue=new MyQueue(6);
  myQueue.enQueue(3);
  myQueue.enQueue(5);
  myQueue.enQueue(6);
  myQueue.enQueue(8);
  myQueue.enQueue(3);
  myQueue.enQueue(1);
  myQueue.deQueue();
  myQueue.deQueue();
  myQueue.deQueue();
  myQueue.deQueue();
  myQueue.enQueue(2);
  myQueue.enQueue(4);
  myQueue.enQueue(9);
  myQueue.output(3);
}

4. 时间复杂度

循环队列不但充分利用了数组的空间,还避免了数组元素的整体移动的麻烦。

数组实现的循环队列,出队列和入队列的时间复杂度都为O(1).

5. 栈和队列的应用

栈的应用

栈的输出顺序和输入顺序相反,所以栈通常用于对于“历史”的回溯,也就是逆流而上追溯“历史”。

例如:实现递归的逻辑,就可以用栈来代替,因为栈可以回溯方法的调用链。

栈还有一个著名的应用场景:面包屑导航,使用户在浏览页面是可以轻松地回溯到上一级或者更上一级的页面。

队列的应用

队列的输出顺序和输入顺序相同,因此队列通常用于对“历史”的回放,也就是按照“历史”顺序,把“历史”重演一遍。

例如: 在多线程中,争夺公平锁的等待队列,就是按照访问顺序来决定线程在队列中的次序的。

网络爬虫实现网站抓取时,也是把待抓取的网站URL存在队列中,再按照存入队列的顺序来进行依次抓取和解析的。

双端队列

双端队列:其实就是综合了栈和队列的优点,对双端队列来说,从队一端可以入队或出队,从队尾一端也可以入队或出队。

优先队列

还有一种队列,它遵循的不是先入先出,而是谁的优先级最高,谁先出队。优先队列已经不属于线性数据结构的范畴了,它是基于二叉堆实现的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值