记得说桟的时候用了羽毛球的例子:羽毛球盒只有一个端口,取出和放入都得从这个口进行,并且放入和取出的原则遵循“后入先出”的原则。而队列与桟的原则相反,桟的原理就好比这个羽毛球盒子是两头开的,放入的时候从一个口放入,而取出的时候从另一端取出,这样就使得先放入的先取出,后放入的后取出。这种先进先出的数据结构就是队列。
说的官方一点,队列就是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。队列是一种FIFO(先进先出)的线性表,允许插入的一端为队尾,允许删除的一端为队头。队列的实现方式有两种:一种是顺序存储结构,一种是链式存储结构。
首先来看顺序存储结构以及入队出队操作,如下图:
入队列:从队尾插入
出队列:从队头删除
下下面是队列的顺序存储结构ArrayQueue
其中队列头为数组头,队列尾为数组尾,队列中包含有获取队列中元素位置、插入、删除、清空队列等操作
ArrayQueue实现:
package ArrayQueue;
import java.util.Arrays;
/**
* Created by Administrator on 2017/5/27.
*/
public class ArrayQueue<T> {
private final int DEFAULT_SIZE = 10;//设置默认尺寸
private int capacity;//保存当前数组长度
private int addCapacity;//设置当超出原数组长度时增加的长度
private Object[] elements;//初始化队列数组
private int size;//保存队列中元素的个数
//创建默认长度的空队列
public ArrayQueue(){
capacity = DEFAULT_SIZE;
elements = new Object[capacity];
}
//创建指定长度的空队列
public ArrayQueue(int capacity){
this.capacity = capacity;
elements = new Object[capacity];
}
/**
* 创建指定长度的空队列,并指定超出数组范围后的增量
* @param capacity 设置指定长度
* @param addCapacity 设置增量
*/
public ArrayQueue(int capacity,int addCapacity){
this.capacity = capacity;
this.addCapacity = addCapacity;
elements = new Object[capacity];
}
//获取队列的长度
public int getSize(){
return size;
}
//判断队列是否为空队列
public boolean isEmpty(){
return size == 0;
}
//确保数组长度,如果超出就进行拓展
private void ensureCapacity(int inputCapacity){
//如果输入的数组长度大于原有数组的长度
if (inputCapacity > capacity) {
//若果有设定数组增量
if (addCapacity > 0)
while (inputCapacity > capacity)
//按照增量扩容,直到大于所需的数组容量
capacity += inputCapacity;
//如果未设定数组增量
else
while (inputCapacity > capacity)
//将capacity左移,使其为大于所需容量
capacity <<= 1;
//扩容后,将原数组复制到新数组中
elements = Arrays.copyOf(elements, capacity);
}
}
//入队列:向队尾添加一个元素
public void add(T element){
//确保数组长度
ensureCapacity(size+1);
//元素进栈
elements[size++] = element;
}
//出队列:移出队头元素
//同时返回移出的元素
public T remove(){
//如果是空队列
if (isEmpty())
return null;
T element = (T) elements[0];
//释放队列头元素并将长度减一
elements[0] = null;
size--;
//将队列头后的元素整体前移
for (int i = 1;i<size;i++)
elements[i-1] = elements[i];
return element;
}
//获取队列头元素
public T getTop(){
return (T)elements[0];
}
//清空队列
public void clear(){
for (int i = 0;i<size;i++)
elements[i] = null;
size = 0;
}
public String toString(){
if (isEmpty())
return "[]";
else {
StringBuilder sb = new StringBuilder("[");
for (int i = 0;i < size;i++)
sb.append(elements[i].toString()+" ");
sb.append("]");
int len = sb.length();
return sb.delete(len-2,len-1).toString();
}
}
}
测试代码:
package ArrayQueue;
/**
* Created by Administrator on 2017/5/27.
*/
public class ArrayQueueTest {
public static void main(String[] args) {
ArrayQueue<String> as = new ArrayQueue<String>();
System.out.println("原队列中的元素: "+as);
System.out.println("----------入队列啦----------");
//入队列
as.add("haha");
as.add("hehe");
as.add("xixi");
as.add("hiahia");
as.add("heihei");
System.out.println("入队列后队列中所含元素: "+as);
//获取队列头元素
System.out.println("队列中队列头元素为: "+as.getTop());
//获取栈中元素个数
System.out.println("当队列中元素个数为: "+as.getSize());
//出栈
System.out.println("----------出队列啦----------");
as.remove();
System.out.println("出队列后队列中所含元素: "+as);
//获取栈顶元素
System.out.println("队列头元素为: "+as.getTop());
//获取栈中元素个数
System.out.println("当前队列中元素个数为: "+as.getSize());
//清空线队列
as.clear();
System.out.println("清空队列");
System.out.println("清空后队列是否为空: "+as.isEmpty());
}
}
测试结果:
原队列中的元素: []
----------入队列啦----------
入队列后队列中所含元素: [haha hehe xixi hiahia heihei]
队列中队列头元素为: haha
当队列中元素个数为: 5
----------出队列啦----------
出队列后队列中所含元素: [hehe xixi hiahia hiahia]
队列头元素为: hehe
当前队列中元素个数为: 4
清空队列
清空后队列是否为空: true
Process finished with exit code 0
然后来看链式存储结构以及入队出队操作,如下图:
下面是队列的链式存储结构LinkListQueue
其中队列头为链表头,队列尾为链表尾,队列中包含有获取队列中元素位置、插入、删除、清空队列等操作
LinkListQueue实现:
package LinkListQueue;
/**
* Created by Administrator on 2017/5/27.
*/
public class LinkListQueue<T> {
//定义一个内部类Node代表链表的节点
private class Node{
private T data;//保存数据
private Node next;//指向下一个节点的引用
//无参构造器
public Node(){}
//初始化全部属性的构造器
public Node(T data,Node next){
this.data = data;
this.next = next;
}
}
private Node header;//保存头结点
private Node tail;//保存尾节点
private int size;//保存已含有的结点数
//创建空链表
public LinkListQueue(){}
//返回链表长度
public int getSize(){
return size;
}
//获取队列指定位置的结点
public Node getNodeByIndex(int index){
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("获取位置超过了链表长度范围");
Node current = header;//从链表表头开始遍历
for (int i = 0;i<size && current != null;i++,current = current.next)
if (i == index)
return current;
return null;
}
//获取队列处指定索引处的元素
public T getElement(int index){
return this.getNodeByIndex(index).data;
}
//按值查找所在队列的位置
public int getIndex(T element){
Node current = header;
for (int i = 0;i < size && current != null;i++,current = current.next)
if (current.data.equals(element))
return i;
return -1;
}
//获取队列头元素
public T getTop(){
return (T)header.data;
}
//在队列中添加元素
public void add(T element){
//如果队列为空
if (header == null){
header = new Node(element, null);
tail = header;//空链表中头尾结点指向同一个
}
else {
Node newNode = new Node(element,null);//创建新结点
tail.next = newNode;//尾结点的next指向新结点
tail = newNode;//将新结点作为尾结点
}
size++;
}
//取出队列中的元素
public T remove(){
Node del = null;
//删除的是头结点
del = header;
header = header.next;
del.next = null;
size--;
return del.data;
}
//判断链表是否为空
public boolean isEmpty(){
return size == 0;
}
//清空线性表
public void clear(){
//将头结点和尾结点设为空
header = null;
tail = null;
size = 0;
}
public String toString(){
if (isEmpty())
return "[]";
else {
StringBuilder sb = new StringBuilder("[");
for (Node current = header;current != null;current = current.next)
sb.append(current.data+"->").toString();
int len = sb.length();
return sb.delete(len-2,len).append("]").toString();
}
}
}
测试代码:
package LinkListQueue;
/**
* Created by Administrator on 2017/5/27.
*/
public class LinkListQueueTest {
public static void main(String[] args) {
LinkListQueue<String> ls = new LinkListQueue<String>();
System.out.println("原队列中的元素: "+ls);
System.out.println("----------入队列啦----------");
//入队列
ls.add("haha");
ls.add("hehe");
ls.add("xixi");
ls.add("hiahia");
ls.add("heihei");
System.out.println("入队列后队列中所含元素: "+ls);
//获取队列头元素
System.out.println("队列中队列头元素为: "+ls.getTop());
//获取栈中元素个数
System.out.println("当队列中元素个数为: "+ls.getSize());
//出栈
System.out.println("----------出队列啦----------");
ls.remove();
System.out.println("出队列后队列中所含元素: "+ls);
//获取栈顶元素
System.out.println("队列头元素为: "+ls.getTop());
//获取栈中元素个数
System.out.println("当前队列中元素个数为: "+ls.getSize());
//清空线队列
ls.clear();
System.out.println("清空队列");
System.out.println("清空后队列是否为空: "+ls.isEmpty());
}
}
测试结果:
原队列中的元素: []
----------入队列啦----------
入队列后队列中所含元素: [haha->hehe->xixi->hiahia->heihei]
队列中队列头元素为: haha
当队列中元素个数为: 5
----------出队列啦----------
出队列后队列中所含元素: [hehe->xixi->hiahia->heihei]
队列头元素为: hehe
当前队列中元素个数为: 4
清空队列
清空后队列是否为空: true
Process finished with exit code 0