队列我们知道是先进先出的数据结构,队首出队,队尾进队
head节点方便我们在链表的头部进行删除和添加操作
为了方便我们在链表的尾部进行操作,我们用tail节点来表示链表的尾部
tail 节点也就是待添加元素之前的节点的位置,所以在tail处添加一个节点是非常容易的
而如果要删除tail处的节点,需要找到tail节点之前的位置,需要从链首开始遍历
结论:tail节点适合插入元素,不适合删除元素
head节点方便插入,删除元素,
所以我们从head端删除元素,从tail端插入元素
由于没有dummyHead,要注意链表为空的情况
队列的接口类
public interface Queue<E> {
int getSize();
//判空
boolean isEmpty();
//入队
void enqueue(E e);
//出队
E dequeue();
//得到队首元素
E getFront();
}
接口实现类之链表的节点定义
private class Node{
public E e;//存储数据
public Node next;//指向下一个节点的位置
public Node(E e, Node next){
this.e = e;
this.next = next;
}
public Node(E e){
this(e,null);
}
public Node(){
this(null,null);
}
@Override
public String toString() {
return e.toString();
}
}
成员变量及构造函数
private Node head ,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){
tail = new Node(e);
head = tail;
}else{
tail.next = new Node(e);
tail = tail.next;
}
size++;
}
//出队
@Override
public E dequeue() {
if (isEmpty()){
throw new IllegalArgumentException("队列为空,不能进行出队操作!");
}
Node cur = head;//被删除的节点
head = head.next;
cur.next = null;
//如果队列中之剩下一个元素,此时tail还指向cur
if (head == null){
tail = null;
}
size--;
return cur.e;
}
@Override
public E getFront() {
if (isEmpty()){
throw new IllegalArgumentException("队列为空,不能进行此操作!");
}
return head.e;
}
@Override
public String toString() {
StringBuilder res = new StringBuilder();
res.append("Queue: front ");
Node cur = head;
while(cur!=null){
res.append(cur+"->");
cur = cur.next;
}
res.append("NULL tail");
return res.toString();
}
测试方法:
public static void main(String[] args) {
LinkedListQueue<Integer> queue = new LinkedListQueue<>();
for (int i = 0; i <10; i++) {
queue.enqueue(i);
System.out.println(queue);
if (i%3==2){
queue.dequeue();
System.out.println(queue);
}
}
}
测试结果: