A Interface Deque
Objective
Entender Deque (pronuncia-se "deck"): uma Queue que ela estende para uma fila de duas pontas (double-ended queue). Filas de duas pontas podem funcionar como filas padrão FIFO (first-in, first-out), ou como pilhas LIFO (last-in, first-out) — Deque adiciona métodos para operar explicitamente em qualquer uma das pontas, além de push()/pop() para o idioma de pilha.
Use Cases
- Adicionar ou remover elementos em qualquer uma das pontas de uma sequência, em vez de só na cabeça como em
Queue. - Usar um único tipo tanto como fila FIFO (
addLast+pollFirst) quanto como pilha LIFO (push+pop), dependendo de qual par de métodos é chamado. - Remover um valor específico do início ou do fim da sequência, em vez da cabeça, com
removeFirstOccurrence/removeLastOccurrence. - Percorrer os elementos da cauda para a cabeça com
descendingIterator()em vez de manter uma estrutura invertida separada. - Trabalhar com um deque de capacidade restrita, onde "sem mais espaço" precisa ser tratado como exceção ou como booleano, dependendo do call site.
Deep Dive
Deque estende Queue
javainterface Deque<E>E especifica o tipo dos objetos que o deque vai armazenar. Tudo que Queue declara continua disponível, mas onde Queue só expõe a cabeça, Deque dá acesso explícito às duas pontas.
Adicionando em qualquer ponta: addFirst/addLast vs. offerFirst/offerLast
javaDeque<Integer> d = new ArrayDeque<>();
d.addFirst(1); // add to the head
d.addLast(2); // add to the tailjavaDeque<Integer> bounded = new ArrayDeque<>(1);
boolean added = bounded.offerFirst(9); // reports failure instead of throwingaddFirst/addLast lançam IllegalStateException se um deque de capacidade restrita está sem espaço; offerFirst/offerLast retornam false em vez disso.
Olhando sem remover: getFirst/getLast vs. peekFirst/peekLast
javaDeque<String> d = new ArrayDeque<>(List.of("a", "b", "c"));
d.getFirst(); // "a" — throws NoSuchElementException if empty
d.peekFirst(); // "a" — returns null if empty
d.getLast(); // "c"
d.peekLast(); // "c"Removendo de uma ponta: removeFirst/removeLast vs. pollFirst/pollLast
javad.removeFirst(); // removes and returns "a" — throws NoSuchElementException if empty
d.pollFirst(); // removes and returns the new head — null if empty
d.removeLast();
d.pollLast();Removendo um valor específico: removeFirstOccurrence / removeLastOccurrence
javaDeque<String> d = new ArrayDeque<>(List.of("a", "b", "a"));
d.removeFirstOccurrence("a"); // true — removes the first "a", leaves [b, a]
d.removeLastOccurrence("a"); // true — removes the remaining "a", leaves [b]Diferente de removeFirst/removeLast, esses métodos buscam por valor e reportam sucesso como um boolean em vez de lançar exceção.
Deque como pilha: push e pop
javaDeque<Integer> stack = new ArrayDeque<>();
stack.push(1); // equivalent to addFirst(1)
stack.push(2); // equivalent to addFirst(2)
stack.pop(); // 2 — equivalent to removeFirst(), LIFO orderpush() adiciona na cabeça e pop() remove da cabeça, então usar esse par transforma o mesmo Deque em uma pilha em vez de uma fila.
Iteração reversa
javaDeque<Integer> d = new ArrayDeque<>(List.of(1, 2, 3));
Iterator<Integer> it = d.descendingIterator(); // walks 3, 2, 1Trade-offs
Um deque de capacidade restrita falha de duas formas diferentes dependendo de qual método é chamado —
addFirst/addLastlançam exceção,offerFirst/offerLastreportamfalse:javaDeque<Integer> d = new ArrayDeque<>(1); d.addFirst(1); d.addFirst(2); // IllegalStateException: full Deque<Integer> d2 = new ArrayDeque<>(1); d2.addFirst(1); boolean ok = d2.offerFirst(2); // false, no exceptiongetFirst/getLast lançam exceção em um deque vazio, peekFirst/peekLast não — a mesma divisão de
element()/peek()deQueue, agora dobrada nas duas pontas:javaDeque<String> empty = new ArrayDeque<>(); empty.getFirst(); // NoSuchElementException empty.peekFirst(); // nullremoveFirstOccurrence/removeLastOccurrence reportam falha em vez de lançar exceção, diferente de removeFirst/removeLast — buscar um valor que não está presente simplesmente retorna
false, enquanto remover de um deque vazio por posição lança exceção:javaDeque<String> d = new ArrayDeque<>(List.of("a")); d.removeFirstOccurrence("z"); // false — not found, no exception d.removeFirst(); // "a" d.removeFirst(); // NoSuchElementException — now emptypush()/pop() e os offer()/poll() herdados de Queue não concordam sobre qual ponta é "a frente" —
push/popoperam na cabeça (LIFO), enquantooffer/polloperam entra-na-cauda-sai-na-cabeça (FIFO); misturar os dois idiomas na mesma instância deDequeproduz uma ordem de percurso que depende de qual par de métodos foi usado para construí-la, não só dos dados em si.