1.概述
上一篇博客我们拒了羽毛球筒的例子来类比栈这种数据结构,这次我们用排队这种模型来类比我们接下来要说的数据结构——队列。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。
队列的数据元素又称为队列元素。在队列中插入一个队列元素称为入队,从队列中删除一个队列元素称为出队。因为队列只允许在一端插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出(FIFO—first in first out)线性表。
我们拿单向队列举例。
入队示例:
出队示例:
队列分为:
①、单向队列(Queue):只能在一端插入数据,另一端删除数据。
②、双向队列(Deque):每一端都可以进行插入数据和删除数据操作。
③、优先级队列(Priority):优先级队列是比栈和队列更专用的数据结构,在优先级队列中,数据项按照关键字进行排序,关键字最小(或者最大)的数据项往往在队列的最前面,而数据项在插入的时候都会插入到合适的位置以确保队列的有序。
2.数组实现简单的单向队列
public class ArrayQueue {
private final Object[] data;
private final int maxSize;
private int currentSize;
private int front;
private int tail;
public ArrayQueue(int maxSize){
if (maxSize <= 0) {
throw new IllegalArgumentException("容量应该大于0 : " + maxSize);
}
this.maxSize = maxSize;
data = new Object[this.maxSize];
this.front = -1;
this.tail = -1;
this.currentSize = 0;
}
public void insert(Object obj){
if(currentSize == maxSize){
throw new IllegalArgumentException("队列已经满了,不能插入数据");
}else{
if(tail == -1 && front == -1 ){ //为空的时候,当remove掉最后一个元素的时候将front和tail都重置
front ++;
tail ++;
currentSize++;
data[front] = obj;
}else{
tail = (tail+1)%maxSize;
currentSize++;
data[tail] = obj;
}
}
}
public Object remove(){
Object rtn = null;
if(currentSize == 1){
currentSize--;
rtn = data[front]; /*先取值*/
data[front] = null;
front = -1;
tail = -1;
}else if(currentSize >1){
currentSize--;
rtn = data[front];
data[front] = null;
front = (front+1)%maxSize;
}
return rtn;
}
public boolean isEmpty(){
return currentSize ==0;
}
public boolean isFull(){
return currentSize == maxSize;
}
public void display(){
if(isEmpty()){
System.out.print("队列为空");
}else{
System.out.print("[ ");
for(Object o : data){
System.out.print(o+" ");
}
System.out.print(" ]");
}
System.out.println();
}
public static void main(String[] args) {
ArrayQueue arrayQueue = new ArrayQueue(5);
arrayQueue.insert("0");
arrayQueue.insert("1");
arrayQueue.insert("2");
arrayQueue.insert("3");
arrayQueue.insert("4");
arrayQueue.display();
System.out.println("//");
System.out.println(arrayQueue.remove());
System.out.println(arrayQueue.remove());
arrayQueue.display();
System.out.println("//");
arrayQueue.insert("5");
arrayQueue.display();
System.out.println("//");
System.out.println(arrayQueue.remove());
System.out.println(arrayQueue.remove());
System.out.println(arrayQueue.remove());
arrayQueue.display();
System.out.println("//");
arrayQueue.insert("6");
arrayQueue.display();
}
}
输出
[ 0 1 2 3 4 ]
//
0
1
[ null null 2 3 4 ]
//
[ 5 null 2 3 4 ]
//
2
3
4
[ 5 null null null null ]
//
[ 5 6 null null null ]
3.双端队列
双端队列就是一个两端都是结尾或者开头的队列, 队列的每一端都可以进行插入数据项和移除数据项,这些方法可以叫做:insertRight()、insertLeft()、removeLeft()、removeRight()
1)如果严格禁止调用insertLeft()和removeLeft()(或禁用右端操作),那么双端队列的功能就和前面讲的栈功能一样。
2)如果严格禁止调用insertLeft()和removeRight(或相反的另一对方法),那么双端队列的功能就和单向队列一样了。
4.数组实现简单的优先级队列(数字越大优先级越高,优先remove最大的)
public class PriorityArrayQueue {
private final int size;
private final int[] data;
private int currentSize;
public PriorityArrayQueue(int size){
if(size <=0){
throw new IllegalArgumentException("容量应该大于0 : " + size);
}
this.size = size;
data = new int[this.size];
currentSize = 0;
}
public void insert(int value){
if(value < 0){
System.out.println("不允许添加小于0的数");
}
if(currentSize == size){
System.out.println("队列已经满了");
}else if(currentSize == 0){
data[0] = value;
currentSize++;
}else{
data[currentSize] = value;
for (int i = 0; i < currentSize; i++) {
if(data[currentSize]<data[i]){
int tmp = data[currentSize];
data[currentSize] = data[i];
data[i] = tmp;
}
}
currentSize++;
}
}
public int remove(){
int rtn = -1;
if(currentSize > 0){
rtn = data[currentSize-1];
data[currentSize-1] = -1;
currentSize--;
}
return rtn;
}
public void display(){
if(currentSize == 0){
System.out.println("队列为空");
}
System.out.print("[ ");
for(int i : data){
System.out.print(i+" ");
}
System.out.print(" ]");
System.out.println();
}
public static void main(String[] args) {
PriorityArrayQueue priorityArrayQueue = new PriorityArrayQueue(3);
priorityArrayQueue.insert(4);
priorityArrayQueue.insert(2);
priorityArrayQueue.insert(1);
priorityArrayQueue.display();
System.out.println("/");
priorityArrayQueue.remove();
priorityArrayQueue.display();
System.out.println("/");
}
}
输出
[ 1 2 4 ]
/
[ 1 2 -1 ]
/