概述
双端队列、队列、栈对比
注1:
Java 中 LinkedList 即为典型双端队列实现,不过它同时实现了 Queue 接口,也提供了栈的 push pop 等方法
注2:
不同语言,操作双端队列的方法命名有所不同,参见下表
![]()
吐槽一下 leetCode 命名比较 low
常见的单词还有 enqueue 入队、dequeue 出队
接口定义
public interface Deque<E> {
boolean offerFirst(E e);
boolean offerLast(E e);
E pollFirst();
E pollLast();
E peekFirst();
E peekLast();
boolean isEmpty();
boolean isFull();
}
基于双向环形链表实现双端队列
/**
* @BelongsProject: arithmetic
* @BelongsPackage: com.hzp.algorithm.deque
* @Author: ASUS
* @CreateTime: 2023-09-30 09:31
* @Description: TODO 基于双向环形链表实现双端队列
* @Version: 1.0
*/
public class LinkedListDeque<E> implements Deque<E>,Iterable<E>{
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> sentinel = new Node<>(null, null, null);
int capacity;
int size;
public LinkedListDeque(int capacity) {
//初始化哨兵时,双向链表的头是指向尾,尾也指向头
sentinel.next = sentinel;
sentinel.prev = sentinel;
this.capacity = capacity;
}
//a added b
@Override
public boolean offerFirst(E e) {
if (isFull()) {
return false;
}
size++;
Node<E> a = sentinel;
Node<E> b = sentinel.next;
Node<E> offered = new Node<>(a, e, b);
a.next = offered;
b.prev = offered;
return true;
}
@Override
public boolean offerLast(E e) {
if (isFull()) {
return false;
}
size++;
Node<E> a = sentinel.prev;
Node<E> b = sentinel;
Node<E> offered = new Node<>(a, e, b);
a.next = offered;
b.prev = offered;
return true;
}
@Override
public E pollFirst() {
if (isEmpty()) {
return null;
}
Node<E> a = sentinel;
Node<E> polled = sentinel.next;
Node<E> b = polled.next;
a.next = b;
b.prev = a;
size--;
return polled.value;
}
@Override
public E pollLast() {
if (isEmpty()) {
return null;
}
Node<E> polled = sentinel.prev;
Node<E> a = polled.prev;
Node<E> b = sentinel;
a.next = b;
b.prev = a;
size--;
return polled.value;
}
@Override
public E peekFirst() {
if (isEmpty()) {
return null;
}
return sentinel.next.value;
}
@Override
public E peekLast() {
if (isEmpty()) {
return null;
}
return sentinel.prev.value;
}
@Override
public boolean isEmpty() {
return size==0;
}
@Override
public boolean isFull() {
return size==capacity;
}
@Override
public Iterator<E> iterator() {
return new Iterator<E>() {
Node<E> p=sentinel.next;
@Override
public boolean hasNext() {
return p!=sentinel;
}
@Override
public E next() {
E value = p.value;
p=p.next;
return value;
}
};
}
}
基于循环数组实现双端队列
思路:
/* h - head:头指针 t - tail:尾指针 我们以索引为0为低 索引高为顶 h t 索引: 0 1 2 3 a offerLast(a) 先添加元素 tail++ :当tail超过了数组长度-1的索引时,我们可以利用之前学习的取模运算,但是我们这里又有一个新方法来限定head、tail的索引范围:inc()、dec() offerLast(b) offerFirst(c) 先 head-- 再添加元素 :head低于数组索引0的长度时,我们可以利用之前学习的取模运算 pollFirst() 先获取要移除的值 head++: pollLast() 先 tail-- 再获取要移除的值 head == tail 空 head ~ tail == 数组长度-1 满 */
代码:
/**
* @BelongsProject: arithmetic
* @BelongsPackage: com.hzp.algorithm.deque
* @Author: ASUS
* @CreateTime: 2023-09-30 09:59
* @Description: TODO 基于循环数组实现双端队列
* @Version: 1.0
*/
public class ArrayDeque1<E> implements Deque<E>,Iterable<E> {
E[] array;
int head;//头指针 无须初始化,全局
int tail;//尾指针 无须初始化,全局
@SuppressWarnings("all")
public ArrayDeque1(int capacity) {
//注意:循环数组,我们的tail的特点:停下来的位置不存储, 会浪费一个位置
array = (E[]) new Object[capacity + 1];
}
/*
h
t
0 1 2 3
a b
*/
static int inc(int i, int length) {
if (i + 1 >= length) {
return 0;
}
return i + 1;
}
/*
h
t
0 1 2 3
a b
*/
static int dec(int i, int length) {
if (i - 1 < 0) {
return length - 1;
}
return i - 1;
}
@Override
public boolean offerFirst(E e) {
if (isFull()) {
return false;
}
head = dec(head, array.length);
array[head] = e;
return true;
}
@Override
public boolean offerLast(E e) {
if (isFull()) {
return false;
}
array[tail] = e;
tail = inc(tail, array.length);
return true;
}
@Override
public E pollFirst() {
if (isEmpty()) {
return null;
}
E e = array[head];
array[head] = null; // help GC
head = inc(head, array.length);
return e;
}
@Override
public E pollLast() {
if (isEmpty()) {
return null;
}
tail = dec(tail, array.length);
E e = array[tail];
array[tail] = null; // help GC
return e;
}
@Override
public E peekFirst() {
if (isEmpty()) {
return null;
}
return array[head];
}
@Override
public E peekLast() {
if (isEmpty()) {
return null;
}
return array[dec(tail, array.length)];
}
@Override
public boolean isEmpty() {
//head == tail 空
return head==tail;
}
/*
h
t
0 1 2 3
a b c
当执行offerLast
tail>head
3-0==array.length-1
*/
/*
h
t
0 1 2 3
c b a
当执行offerFirst
tail<head
head-tail==1
*/
@Override
public boolean isFull() {
if (tail > head) {
return tail - head == array.length - 1;
} else if (tail < head) {
return head - tail == 1;
} else {
return false;
}
}
@Override
public Iterator<E> iterator() {
return new Iterator<E>() {
int p = head;
@Override
public boolean hasNext() {
return p != tail;
}
@Override
public E next() {
E e = array[p];
p = inc(p, array.length);
return e;
}
};
}
}