队列的链式存储结构及实现:
类似于使用链式结构保存线性表,也可以采用链式结构来保存队列的元素,采用链式存储结构的队列也被称为链队列。
对于链队列而言,由于程序需要从rear端添加元素,然后从front端删除元素,因此考虑对链队列增加front、rear两个引用变量,使他们分别指向链队列的头、尾两个节点。如下图所示:
由于链队列采用链式存储结构保存数据元素,该队列允许添加无限多个数据元素,因此链队列不会出现列满的问题。
1、插入队列
对于链队列而言,插入操作的实现非常简单,只要创建一个新节点,让原rear节点的next指向新节点,在让rear指向新节点即可。如下图所示链队列的插入操作:
2、移除队列
对于链队列而言,删除操作的实现也是非常的简单,只要将原front节点指向原front节点的next节点,当然不要忘记释放原front节点的引用。如下图所示链队列的移除操纵:
(1)插入:在rear端插入元素。
(2)移除:在front端删除元素。
(3)访问:在front端访问元素。
对于双端队列,由于它可以从两端分别进行插入、删除操作,如果程序将所有的插入、删除操作固定在一端进行,这个双端队列就变成了前面的栈。由此可见,Deque和Queue。Stack之间的关系如下图所示。
从上面图可以看出,双端队列(Deque)既是Queue的子接口,也可说是Stack(虽然jdk并未把Stack作为一个接口)的子接口。因此,Deque既可以当做队列来使用,又可以当做栈来使用。
由此可见,Deque是Queue'和Stack‘的混合而成的一种特殊线性表。
JDK虽然提供一个古老的Stack'类,但现在不推荐开发者使用这个古老的栈实现,而是使用Deque的实现作为栈的使用。
JDK为Deque提供两种ArrayDeque、linkedList这两个常见的实现类,其中ArrayDeque是顺序存储结构实现的双端队列。而LinkedList是链式存储结构实现的双端队列。
在前面的双向链表中还提到了LinkedList代表一种双向、链式存储结构的循环线性表,这里有提到了LinkedList代表线程安全的、链式结构的双端队列,由此可见,LinkedList实在是一个功能非常强大的集合类。事实上,LinkedList几乎是Java集合框架中方法最多的类。
关于JDK提供的线性表、队列、栈的类图如下所示:
从上图可以看出。JDK提供的工具类非常强大,它分别代表线性表、队列、栈三种数据结构提供了两种实现:顺序结构和链式结构。虽然LinkedList工具类的功能非常强大,既可以作为线性表来使用、又可以作为队列来使用,还可作为栈来使用,但对大部分程序而言,使用Arraylist和ArrayDeque时性能可能比LinkedList更好。
类似于使用链式结构保存线性表,也可以采用链式结构来保存队列的元素,采用链式存储结构的队列也被称为链队列。
对于链队列而言,由于程序需要从rear端添加元素,然后从front端删除元素,因此考虑对链队列增加front、rear两个引用变量,使他们分别指向链队列的头、尾两个节点。如下图所示:
由于链队列采用链式存储结构保存数据元素,该队列允许添加无限多个数据元素,因此链队列不会出现列满的问题。
1、插入队列
对于链队列而言,插入操作的实现非常简单,只要创建一个新节点,让原rear节点的next指向新节点,在让rear指向新节点即可。如下图所示链队列的插入操作:
2、移除队列
对于链队列而言,删除操作的实现也是非常的简单,只要将原front节点指向原front节点的next节点,当然不要忘记释放原front节点的引用。如下图所示链队列的移除操纵:
下面是代码实现:
public class LinkQueue <T> {
private class Node{
private T data;
private Node next;
@SuppressWarnings("unused")
public Node(){}
public Node(T element, Node next){
this.data = element;
this.next = next;
}
}
//代表链式队列的大小
private int size;
//链式队列的链队首
private Node front;
//链式队列的链队尾
private Node rear;
public LinkQueue(){
size = 0;
front = null;
rear = null;
}
public LinkQueue(T element){
rear = new Node(element, null);
front = rear;
size ++;
}
//返回链式队列的长度
public int length(){
return size;
}
//判断队列是否为空
public boolean isEmpty(){
return size == 0;
}
//向rear端队尾插入元素
public void add(T element){
if(isEmpty()){
rear = new Node(element, null);
front = rear;
}else{
rear.next = new Node(element, null);
rear = rear.next;
}
size ++;
}
//从front端队首移除元素
public T remove(){
exceptionForRemove();
Node oldNode = front;
front = front.next;
oldNode.next = null;
size --;
return oldNode.data;
}
//返回链式队列的堆首元素,但不删除
public T element(){
return front.data;
}
//清空链式队列
public void clear(){
front = null;
rear = null;
size = 0;
}
//toString 方法
public String toString(){
if(isEmpty()){
return "[]";
}else{
StringBuffer sb = new StringBuffer("[");
for(Node current = front; current != null; current = current.next){
sb.append(current.data.toString() + ",");
}
return sb.toString().substring(0, sb.length() - 1) + "]";
}
}
private void exceptionForRemove(){
if(isEmpty()){
throw new IndexOutOfBoundsException("链式队列为空异常");
}
}
}
测试代码如下:
import com.yc.list.LinkQueue;
public class LinkQueueTest {
public static void main(String[] args) {
LinkQueue<String> queue = new LinkQueue<String>();
queue.add("aaaa");
queue.add("bbbb");
queue.add("cccc");
System.out.println( "链式队列为: " + queue);
System.out.println();
System.out.println( "移除队首元素: " + queue.remove());
System.out.println( "链式队列为: " + queue);
System.out.println();
queue.add("dddd");
queue.add("eeee");
System.out.println( "添加 dddd和 eeee链式队列为: " + queue);
System.out.println( "此时队首元素为:" + queue.element());
}
}
测试结果为:
上面创建了一个链队列,但不会出现队列“”满“”的情形,因此程序可以不受限制的向链队列中添加元素。
JAVA集合中的队列:
从JDK 1.5开始,java的集合框架提供了一个Queue接口,该接口代表了一个队列。实现该接口或者实现继承了该接口的类可以当做队列来使用。Queue里包含了 6 个方法,用于代表队列
所包含的3个标志性方法,如下所示:(1)插入:在rear端插入元素。
(2)移除:在front端删除元素。
(3)访问:在front端访问元素。
Java为上面每个方法都提供了两个版本:具有特殊返回值的版本和抛出异常的版本。这样就产生了 6 个方法。关于Queue接口里定义的 6 个方法的说明如下表所示:
抛出异常的版本 | 具有特殊返回值的版本 | |
插入 | add(e) | offer(e) |
移除 | remove() | poll() |
访问 | element() | peek() |
Java提供了一个Queue接口,JDK 1.5还为Queue接口提供了一个Deque接口,这个接口代表另外一种特殊的队列--双端队列。
双端队列(有英文单词Deque代表)代表一种特殊的队列,他可以在两端同时进行插入、删除操作。如下图所示:
对于双端队列,由于它可以从两端分别进行插入、删除操作,如果程序将所有的插入、删除操作固定在一端进行,这个双端队列就变成了前面的栈。由此可见,Deque和Queue。Stack之间的关系如下图所示。
从上面图可以看出,双端队列(Deque)既是Queue的子接口,也可说是Stack(虽然jdk并未把Stack作为一个接口)的子接口。因此,Deque既可以当做队列来使用,又可以当做栈来使用。
由此可见,Deque是Queue'和Stack‘的混合而成的一种特殊线性表。
JDK虽然提供一个古老的Stack'类,但现在不推荐开发者使用这个古老的栈实现,而是使用Deque的实现作为栈的使用。
JDK为Deque提供两种ArrayDeque、linkedList这两个常见的实现类,其中ArrayDeque是顺序存储结构实现的双端队列。而LinkedList是链式存储结构实现的双端队列。
在前面的双向链表中还提到了LinkedList代表一种双向、链式存储结构的循环线性表,这里有提到了LinkedList代表线程安全的、链式结构的双端队列,由此可见,LinkedList实在是一个功能非常强大的集合类。事实上,LinkedList几乎是Java集合框架中方法最多的类。
关于JDK提供的线性表、队列、栈的类图如下所示:
从上图可以看出。JDK提供的工具类非常强大,它分别代表线性表、队列、栈三种数据结构提供了两种实现:顺序结构和链式结构。虽然LinkedList工具类的功能非常强大,既可以作为线性表来使用、又可以作为队列来使用,还可作为栈来使用,但对大部分程序而言,使用Arraylist和ArrayDeque时性能可能比LinkedList更好。