Perché std :: stack usa std :: deque per impostazione predefinita?


91

Poiché le uniche operazioni richieste per un contenitore da utilizzare in uno stack sono:

  • indietro()
  • respingere()
  • pop_back ()

Perché il contenitore predefinito per esso è una deque invece di un vettore?

Non deselezionare le riallocazioni di fornire un buffer di elementi prima di front () in modo che push_front () sia un'operazione efficiente? Questi elementi non vengono sprecati dal momento che non verranno mai utilizzati nel contesto di uno stack?

Se non vi è alcun sovraccarico per l'utilizzo di una deque in questo modo invece di un vettore, perché l'impostazione predefinita per priority_queue è un vettore non anche una deque? (priority_queue richiede front (), push_back () e pop_back () - essenzialmente come per lo stack)


Aggiornato in base alle risposte seguenti:

Sembra che il modo in cui deque viene solitamente implementato sia un array di dimensioni variabili di array di dimensioni fisse. Questo fa crescere più velocemente di un vettore (che richiede riallocazione e copia), quindi per qualcosa come uno stack che consiste nell'aggiunta e nella rimozione di elementi, deque è probabilmente una scelta migliore.

priority_queue richiede un'indicizzazione pesante, poiché ogni rimozione e inserimento richiede l'esecuzione di pop_heap () o push_heap (). Questo probabilmente rende il vettore una scelta migliore in questo caso poiché l'aggiunta di un elemento è comunque costante ammortizzata.


1
Il ragionamento nel tuo "aggiornamento" non è del tutto corretto. il vettore normalmente aggiunge e rimuove gli elementi dalla fine più velocemente di una deque. deque è più veloce per far crescere la memoria , non per spingere gli elementi.
Mooing Duck

Risposte:


75

Man mano che il contenitore cresce, una riallocazione di un vettore richiede la copia di tutti gli elementi nel nuovo blocco di memoria. La crescita di un deque alloca un nuovo blocco e lo collega all'elenco dei blocchi: non sono necessarie copie.

Ovviamente puoi specificare di utilizzare un contenitore di supporto diverso, se lo desideri. Quindi, se hai uno stack che sai che non crescerà molto, digli di usare un vettore invece di un deque se questa è la tua preferenza.


1
Ma quando l'elenco dei puntatori ai blocchi cresce, questo elenco deve essere riallocato occasionalmente proprio come un vettore deve; asintoticamente, qualsiasi guadagno di efficienza è nella migliore delle ipotesi un fattore costante. E la manipolazione degli iteratori necessaria per eseguire correttamente push e pop è molto più complicata di std::dequequanto non lo sia std::vector, e queste operazioni probabilmente verranno utilizzate molto più frequentemente delle riallocazioni. Ho difficoltà a credere che std::dequeavrebbe mai battuto std::vectorin pratica.
Marc van Leeuwen

@Michael Burr: Allora perché non usare list, perché deque?
bappak

@ MarcvanLeeuwen riguardo a te, dici che hai difficoltà a credere ... potresti per favore fare un punto di vista chiaro? vuoi dire che ora credi di std::dequeavere una possibilità di battere std::vectorin pratica, o vuoi dire che ne dubiti ancora? Grazie.
aafulei

@fleix Non vedo perché sia ​​così importante se personalmente ho più difficoltà a credere che std::dequefunzionerà così come std::vectornelle applicazioni pratiche. Ma per quel che vale, la mia esperienza personale è che ho bisogno di impilare e accodare strutture dati non per un compito grande e cruciale per la complessità, ma per molte piccole occasioni disseminate nel mio codice. In quanto tale, mi preoccupo di più del comportamento nel piccolo che nel grande; e deque brilla in modo particolarmente opaco. La mia preferenza è di non utilizzare nessuno dei due, ma invece elenchi collegati singolarmente (autoimplementati). Ma il tuo chilometraggio può variare.
Marc van Leeuwen

12

Vedi Herb Sutter's Guru of the Week 54 per i relativi meriti di vector e deque dove entrambi andrebbero bene.

Immagino che l'incoerenza tra priority_queue e queue sia semplicemente che persone diverse li hanno implementati.


2
priority_queue in realtà non usa push / pop_front e i riferimenti ad elementi oltre al primo sono invalidati dalle operazioni di heap. Quindi, nessuno dei vantaggi di deque si applicherebbe, a differenza del caso di una coda normale.
Potatoswatter

9
Inoltre, priority_queuedeve rimanere ordinato, quindi il sovraccarico maggiore di accesso casuale deque::iteratorè più problematico.
Potatoswatter

1
@ Potatoswatter: priority_queueha un "ordine magico" che viene mantenuto, non è ordinato. Tuttavia, il tuo punto resta.
Mooing Duck
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.