队列是一种先进先出的数据结构,它和栈的性质正好相反,但是两者却经常结合在一起实现一些特殊的操作。
1.队列的接口
public interface QueueADT {
//入队
public void enqueue(Object element);
//出队
public Object dequeue();
//返回队首元素
public Object first();
//是否为空
public boolean isEmpty();
//返回队列大小
public int size();
public String toString();
}
2.链表实现队列
public class LinkedQueue implements QueueADT {
// 链表节点类,内部类实现,包含数据域和指针域
class Node {
int data; // 数据域
Node next;// 指针域
public Node(int data) {
this.data = data;
}
}
//指向队首、队尾节点
private Node front,rear;
//维护队列的大小
private int count;
public LinkedQueue() {
front=null;
rear=null;
count=0;
}
//保证出栈或者出队列的是头结点,这样才能完成更新,所以对于栈的入栈操作,是从尾节点开始构造的
//队列的入队操作,是从头结点开始构造的
@Override
public void enqueue(Object element) {
Node node=new Node((Integer)element);
if(isEmpty()){
front=rear=node;
}else{
rear.next=node;
rear=node;
}
count++;
}
@Override
public Object dequeue() {
if(isEmpty()){
System.out.println("队列中没有元素");
System.exit(1);
}
Object result=front.data;
front=front.next;
count--;
return result;
}
@Override
public Object first() {
return front.data;
}
@Override
public boolean isEmpty() {
return (size()==0);
}
@Override
public int size() {
return count;
}
public static void main(String[] args) {
LinkedQueue queue = new LinkedQueue();
System.out.println("依次将0到9入队,然后连续出队5次");
for(int i = 0;i < 10;i++)
queue.enqueue(i);
for(int i = 0;i < 5;i++)
queue.dequeue();
System.out.println("队列的大小为: " + queue.size());
System.out.println("队列为空吗?: " + queue.isEmpty());
System.out.println("队列的头为: " + queue.first());
}
}
//用数组实现队列,如果队首不固定,随着出队操作,数组前面的空间就被浪费,但是如果队首固定,每次出队都要移动所有元素
public class ArrayQueue implements QueueADT {
private Object[] contents;
//由于数组实现,rear是一个整数指针,指向数组的索引即可
private int rear;
private static int SIZE = 10;
public ArrayQueue(){
contents = new Object[SIZE];
rear = 0;
}
public void expand(){
Object[] larger = new Object[size()*2];
for(int index = 0;index < rear;index++)
larger[index] = contents[index];
contents = larger;
}
@Override
public void enqueue(Object element) {
if(rear == contents.length)
expand();
contents[rear] = element;
rear++;
}
@Override
public Object dequeue() {
if(isEmpty()){
System.out.println("队列为空");
System.exit(1);
}
Object result = contents[0];
//为了保证队首固定,每次出队之后都要移动元素
for(int index = 0;index < rear;index++)
contents[index] = contents[index+1];
rear--;
return result;
}
@Override
public Object first() {
return contents[0];
}
@Override
public boolean isEmpty() {
return (size()==0);
}
@Override
public int size() {
return rear;
}
}
4.数组实现循环队列
//使用循环队列可以消除元素频繁移动带来的效率问题,用两个指针分别指向队首和队尾,走到数组末尾时,在数组头部继续入队
public class CircularArrayQueue implements QueueADT{
private Object[] contents;
private int front,rear;//front为队头下标,rear为队尾的下一个元素的下标
private int count;//标记队列元素个数
private static int SIZE = 10;
public CircularArrayQueue(){
contents = new Object[SIZE];
front = -1;
rear = 0;
count = 0;
}
//对栈还有队列进行操作,或者其他类,一般都要特殊考虑一下状态为空或者初始化时的特殊值
@Override
public void enqueue(Object element) {
if(isEmpty()){
contents[0]=element;
front=0;
rear=1;
count++;
}else{
contents[rear]=element;
rear=(rear+1)%contents.length;
count++;
}
}
@Override
public Object dequeue() {
if(isEmpty()){
System.out.println("队列为空!!!");
System.exit(1);
}
Object result = contents[front];
front = (front + 1) % contents.length;
count--;
return result;
}
@Override
public Object first() {
return contents[front];
}
@Override
public boolean isEmpty() {
return (size()==0);
}
@Override
public int size() {
return count;
}
}