链表的结构决定了再链表头进行添加/删除操作时时间复杂度仅为O(1),但是对链表尾部进行操作的时间复杂度为O(n),而队列是一种先进先出的数据结构,既要对队首进行操作,也要对队尾进行操作,所以必须对链表进行一点修改,才能实现时间复杂度为O(1)的队列.
修改的方式就是添加一个尾指针,指向链表的最后一个节点,这个操作只是针对实现队列时的优化,使得在链表尾部添加元素的时间复杂度从O(n)将为O(1),也就是不需要从头到尾遍历,但是在链表尾部删除元素的时间复杂度依然是O(n),因为删除时没有办法获取被删除节点的前一个结点(因为没有使用双向链表).
在链表中使用尾节点要注意链表为空的时候,head和tail都指向null,当链表中只有一个元素的时候,head和tail指向同一个节点.
实现时依然是先创建一个Queue接口类,用于定义队列的一些必要操作,然后创建一个LinkedListQueue类,实现Queue接口就可以了.
具体代码如下:
Queue接口类:
public interface Queue<E> {
public void enqueue(E e);
public E dequeue();
public E getFront();
public int getSize();
public boolean isEmpty();
}
LinkedListQueue实现类:
/**
* 使用带有尾指针的链表实现队列
* @author ChenZhuJi
*
* @param <E>
*/
public class LinkedListQueue<E> implements Queue<E> {
private class Node {
public E e; //节点中存储的数据
public Node next; //下一个节点
public Node(E e,Node next) {
this.e = e;
this.next = next;
}
public Node() {
this(null,null);
}
public Node(E e) {
this(e,null);
}
@Override
public String toString() {
return e.toString();
}
}
private Node head; //头指针
private Node tail; //尾指针
private int size; //节点个数
public LinkedListQueue() {
head = null;
tail = null;
size = 0;
}
/**
* 获取队列中元素个数
*/
@Override
public int getSize() {
return size;
}
/**
* 判断队列是否为空
*/
@Override
public boolean isEmpty() {
return size == 0;
}
/**
* 入队操作
*/
@Override
public void enqueue(E e) {
if(tail == null) {
head = new Node(e);
tail = head;
size++;
} else {
tail.next = new Node(e);
tail = tail.next;
size ++;
}
}
/**
* 出队操作
*/
@Override
public E dequeue() {
if( isEmpty() ) {
throw new IllegalArgumentException("队列为空");
}
Node ret = head;
head = head.next;
ret.next = null;
if(head == null) {
tail = null;
}
size --;
return ret.e;
}
/**
* 获取队头元素
*/
@Override
public E getFront() {
if( isEmpty() ) {
throw new IllegalArgumentException("队列为空");
}
return head.e;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("LinkedListQueue : front ");
Node pre = head;
while(pre != null) {
sb.append(pre.e + "->");
pre = pre.next;
}
sb.append("null tail");
return sb.toString();
}
public static void main(String[] args) {
LinkedListQueue<Integer> llq = new LinkedListQueue<Integer>();
for(int i = 0; i < 5; i++) {
llq.enqueue(i);
System.out.println(llq);
}
llq.dequeue();
System.out.println(llq);
}
}