队列是一种基于先进先出(FIFO)策略的集合类型,只允许在其一端(队尾)进行插入操作,在另一端(对头)进行删除操作。
抽象数据类型
public class Queue<Item> implements Iterable<Item>
队列API | 功能 |
---|---|
void enQueue(Item item) | 添加元素(入队) |
Item deQueue() | 删除元素(出队) |
boolean isEmpty() | 判断队列是否为空 |
int size() | 队列的大小 |
队列的创建
数组实现
其存储结构如下图:
数组实现队列的过程:
假设开始时数组长度为5,如图,当f入队时,此时数组末尾元素已被占用,如果继续向后就会产生下标越界,但此时数组未满,将从头开始入队。这种逻辑上首尾相连的顺序存储结构叫循环队列。当数组满(h入队)时,将数组的长度加倍。
代码如下:
import java.util.Iterator;
/**
* 能动态调整数组大小的循环队列
* @author Gain
*/
public class CycleArrayQueue<Item> implements Iterable<Item> {
private int N;//记录队列大小
//last表示尾元素后一个的索引
private int first,last;//first表示头元素的索引
private Item[] a;
public CycleArrayQueue() {
a = (Item[])new Object[1];
}
public int size() {return N;}
public boolean isEmpty(){return N==0;}
//调整数组大小
public void resizingArray(int num) {
Item[] temp = (Item[])new Object[num];
for(int i=0;i<N;i++) {
temp[i] = a[(first+i)%a.length];
}
a = temp;
first = 0;//数组调整后first,last位置
last = N;
}
public void enQueue(Item item){
//当队列满时,数组长度加倍
if(N==a.length) resizingArray(2*N);
a[last] = item;
last = (last+1)%a.length;//【关键】
N++;
}
public Item deQueue() {
if(isEmpty()) return null;
Item item = a[first];
first = (first+1)%a.length;//【关键】
N--;
//当队列长度小于数组1/4时,数组长度减半
if(N>0 && N<a.length/4) resizingArray(2*N);
return item;
}
//实现迭代器
public Iterator<Item> iterator() {
return new ResizingArrayQueueIterator();
}
private class ResizingArrayQueueIterator implements Iterator<Item> {
private int num=N;
private int current = first;
public boolean hasNext() {
return num>0;
}
public Item next() {
Item item = a[current++];
num--;
return item;
}
}
}
链表实现
存储结构如下图:
代码如下:
import java.util.Iterator;
/**
* 链表实现的队列
* @author Gain
*/
public class LinkedQueue<Item> implements Iterable<Item> {
private Node first,last;//头结点,尾结点
private int N=0;//队列大小
//定义结点
private class Node {
Item item;
Node next;
}
public int size() {return N;}
public boolean isEmpty(){return N==0;}
//入队
public void enQueue(Item item) {
Node oldLast = last;
last = new Node();
last.item = item;
if(isEmpty()) {
first = last;//【要点】
}else {
oldLast.next = last;
}
N++;
}
//出队
public Item deQueue() {
Item item = first.item;
first = first.next;
N--;
if(isEmpty()) last = null;//【要点】
return item;
}
//实现迭代器
public Iterator<Item> iterator() {
return new LinkedQueueIterator();
}
private class LinkedQueueIterator implements Iterator<Item>{
private Node current = first;
public boolean hasNext() {
return current != null;
}
public Item next(){
Item item = current.item;
current = current.next;
return item;
}
}
}
测试
代码如下:
//测试
public class Test {
public static void main(String[] args) {
int[] a = {1,2,4,6,new Integer(10),5};
CycleArrayQueue<Integer> queue1 = new CycleArrayQueue<Integer>();
LinkedQueue<Integer> queue2 = new LinkedQueue<Integer>();
for(int i=0;i<a.length;i++) {
queue1.enQueue(a[i]);
queue2.enQueue(a[i]);
System.out.print(a[i]+" ");
}
System.out.println("入队");
//迭代
for (Integer s : queue1) {
System.out.print(s+" ");
}
System.out.println("出队");
for (Integer s : queue2) {
System.out.print(s+" ");
}
}
}
运行结果:
应用
Josephus问题:
问题描述:N个身陷绝境的人一致同意通过以下方式减少生存人数。他们围成一圈(位置记为0到N-1)并从第一个人开始报数,报到M的人被杀死,直到最后一人留下来。找到不会被杀死的位置。
思路: 需要一个辅助队列,将0到N-1全部依次入队,然后依次出队,再将未被杀死的人(未报到M)入队,构成循环。打印出人们被杀死的顺序,最后一个即为不会被杀死的位置。
import java.util.Scanner;
import queue.LinkedQueue;
/**
* Josephus问题
* @author Gain
*
*/
public class Josephus {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
LinkedQueue<Integer> q = new LinkedQueue<Integer>();
System.out.println("输入人数N:");
int N = sc.nextInt();
System.out.println("输入报数M:");
int M = sc.nextInt();
sc.close();
for(int i=0;i<N;i++) {
q.enQueue(i);
}
while(!q.isEmpty()) {
for(int i=1;i<M;i++) {
q.enQueue(q.deQueue());//【核心代码】
}
System.out.print(q.deQueue() + " ");
}
}
}
运行结果: