1. 前言
- 前文我们分别用链表,数组来实现了栈和队列. 而双端队列可以替代栈和队列并达到二者的效果.
- 我们知道,栈的特点是只在栈顶操作元素,队列的特点是在队头pop元素,在队尾push元素. 而双端队列可以在队头和队尾分别进行pop与push操作.
- 双端队列接口(Deque)有两个主要实现类,其一是ArrayDeque, 其二是LinkedList.本文我们主要探讨用双向循环链表来实现Deque接口,达到LinkedList的效果.
- 为什么要使用双向循环链表,而不是使用双向链表呢?因为我们要对该数据结构进行头尾的操作.为了方便对队头队尾的操作,我们往往会在队头队尾添加哨兵节点,方便我们删除队头队尾元素.如果我们使用双向链表,我们需要在队头和队尾分别设置一个哨兵节点.而我们使用双向循环链表,只需设置一个哨兵节点即可.
2. 双向循环链表模拟双端队列
(1). Deque接口
public interface MyDeque<E>{boolean offerFirst(E e);boolean offerLast(E e);E pollFirst();E pollLast();E peekFirst();E peekLast();boolean isEmpty();boolean isFull();}
(2). 模拟双端队列
//双向链表模拟双端队列
public class MyLinkedList<E> implements MyDeque<E>, Iterable<E> {//Node内部类private static class Node<E> {Node<E> prev;E value;Node<E> next;public Node(Node<E> prev, E value, Node<E> next) {this.prev = prev;this.value = value;this.next = next;}}//哨兵节点Node<E> sential = new Node<>(null, null, null);//头节点Node<E> head = sential;//尾节点Node<E> tail = sential;//双端队列的容量private int capacity;//双端队列的实际大小private int size;public MyLinkedList(int capacity) {this.capacity = capacity;sential.prev = sential;sential.next = sential;}@Overridepublic boolean offerFirst(E e) {//如果双端队列已经满了, 加入失败if(isFull()) {return false;}Node<E> p = new Node<>(sential, e, sential.next);sential.next = p;size++;return true;}@Overridepublic boolean offerLast(E e) {if(isFull()) {return false;}Node<E> p = new Node<>(tail, e, sential);tail.next = p;tail = p;size++;return true;}@Overridepublic E pollFirst() {//如果双端队列已空if (isEmpty()) {return null;}Node<E> p = sential.next;sential.next = p.next;p.next.prev = sential;size--;return p.value;}@Overridepublic E pollLast() {if(isEmpty()) {return null;}Node<E> p = tail.prev;p.next = sential;E value = tail.value;tail = p;size--;return value;}@Overridepublic E peekFirst() {if (isEmpty()) {return null;}return sential.next.value;}@Overridepublic E peekLast() {if(isEmpty()) {return null;}return tail.value;}@Overridepublic boolean isEmpty() {//当head与tail指针都指向了哨兵节点时, 此时双端队列为空return head == tail;}@Overridepublic boolean isFull() {return size > capacity;}@Overridepublic Iterator<E> iterator() {return new Iterator<E>() {Node<E> p = sential.next;@Overridepublic boolean hasNext() {return p != sential;}@Overridepublic E next() {E value = p.value;p = p.next;return value;}};}
}
3. 单元测试
public class MyLinkedListTest {@Testpublic void test1() {MyLinkedList<Integer> deque = new MyLinkedList<>(10);deque.offerFirst(1);deque.offerFirst(2);deque.offerFirst(3);deque.offerFirst(4);deque.offerFirst(5);deque.offerFirst(6);for (Integer element : deque) {System.out.print(element + " ");}//6 5 4 3 2 1}@Testpublic void test2() {MyLinkedList<Integer> deque = new MyLinkedList<>(10);deque.offerLast(1);deque.offerLast(2);deque.offerLast(3);deque.offerLast(4);deque.offerLast(5);deque.offerLast(6);for(Integer element : deque) {System.out.print(element + " ");}}
}