Tasto di aumento e tasto di riduzione in un min-heap binario


16

In molte discussioni sull'heap binario, normalmente solo la chiave di riduzione viene elencata come operazione supportata per un heap min. Ad esempio, CLR capitolo 6.1 e questa pagina di Wikipedia . Perché la chiave di aumento non è normalmente elencata per min-heap? Immagino sia possibile farlo in O (altezza) scambiando iterativamente l'elemento aumentato (x) con il minimo dei suoi figli, fino a quando nessuno dei suoi figli è più grande di x.

per esempio

IncreaseKey(int pos, int newValue)
{
   heap[pos] = newValue;
   while(left(pos) < heap.Length)
   {
      int smallest = left(pos);
      if(heap[right(pos)] < heap[left(pos)])
         smallest = right(pos);
      if(heap[pos] < heap[smallest])
      { 
         swap(smallest, pos);
         pos= smallest;
      }
      else return;
   }   
}

Quanto sopra è corretto? Se no, perché? Se sì, perché la chiave di aumento non è elencata per min-heap?


1
Dopo aver letto tutte le risposte, direi, è una strana omissione, probabilmente causata dal primo utilizzo storicamente di min-heap nell'algoritmo Dijkstra.
maaartinus,

3
Ovviamente puoi sempre implementare il tasto di aumento usando un tasto di cancellazione seguito da un inserimento, e il comando di cancellazione stesso può essere implementato come tasto di riduzione (fino a -∞) seguito da delete-min.
davmac,

Il commento di @maaartinus è la risposta corretta.
max

Risposte:


6

L'algoritmo che suggerisci è semplicemente heapify. E infatti - se aumenti il ​​valore di un elemento in un min-heap, e poi ne accumuli la sottostruttura, finirai con un min-heap legale.


allora perché il CLR o l'elenco Wikipedia non aumentano la chiave per essere un'operazione supportata? In un certo senso mi fa ingannare pensare che non sia possibile in un min-heap
GatotPujo

Sono d'accordo che sia fuorviante, ma non vedo alcun errore nell'algoritmo.
Shaull

5

Il motivo per cui la tua operazione non è elencata, è che non sei semplicemente interessato a tutte le operazioni che possono essere facilmente implementate usando una certa struttura di dati, ma piuttosto il contrario. Dato un insieme di operazioni, qual è il modo più efficiente (in termini di spazio e tempo) per implementare queste operazioni. (Ma ne aggiungo altri più avanti)

Gli heap binari implementano la coda di priorità della struttura di dati astratta, che richiede operazioni is_empty, add_element (una chiave con la sua priorità), find_min ed delete_min. Le code più avanzate consentono anche di ridurre la priorità della chiave (in un min_heap) o addirittura di aumentarla. In effetti, hai dato un'implementazione.

Due osservazioni L'operazione viene utilizzata nella funzione heapify, che costruisce in modo efficiente un heap da un array. In heapify l'operazione viene ripetuta (a partire dall'ultimo tasto).

Quindi, soprattutto, il codice utilizza la posizione del nodo. Per la pura priorità della struttura dei dati che sta tradendo. Tale struttura di dati richiede di eseguire una determinata operazione assegnando una chiave. Quindi, per ridurre o aumentare la priorità di un elemento, dovrai prima localizzarlo. Penso che sia la ragione principale per cui non è elencato.


1
Grazie per la spiegazione. Tuttavia, in CLR la chiave di riduzione ha anche la posizione come nodo come parametro.
GatotPujo

Hai ragione. Non ho trovato un motivo per questa asimmetria nella definizione delle code di priorità nella Sezione 6.5 del CLRS. Nota il tasto di aumento non viene utilizzato in Heapsort, l'applicazione di questo capitolo. Sembra che l'asimmetria tra aumento e diminuzione sia correlata solo al modo in cui viene utilizzata la struttura dei dati, ad esempio nell'algoritmo di Dijkstra. Lì (usando un min-heap) alcuni nodi selezionati potrebbero diventare più urgenti e spostati "in alto" nell'heap.
Hendrik Jan

0

Penso che la prima cosa da considerare sia cos'è un'operazione supportata?

"L'inserimento di un valore con una chiave fissa specifica" (ad es. Per le chiavi prese dal regno intero, l'inserimento con chiave = 3) corrisponde a un'operazione supportata per l'heap min?

No, perché tale operazione può essere banalmente implementata con operazioni supportate più generali. Allo stesso modo, l'inserimento di 2 elementi contemporaneamente può essere fatto con l' insertoperazione esistente .

D'altra parte, l' insertoperazione non può essere definita se non esponendo i dettagli dell'implementazione. È praticamente lo stesso per le operazioni elencate nella pagina di Wikipedia, ad heapifyeccezione, che probabilmente potrebbero essere implementate da una sequenza di insert.

In altre parole, ci sono operazioni elementari fornite sul tipo, che sono strettamente legate ai dettagli di implementazione affinché funzionino bene, e ci sono altre operazioni, che non rispettano quella regola, e quindi possono essere implementate come combinazioni di quelli canonici.

Con questa definizione in mente, pensi che la chiave di aumento potrebbe essere implementata esclusivamente con altre operazioni supportate, senza perdita di prestazioni? In tal caso, allora non è un'operazione supportata dalla definizione precedente, altrimenti potresti avere ragione.

Probabilmente, la definizione di un'operazione supportata che fornisco è mia, per quanto ne so. Non è formale e quindi soggetto a discussione (anche se mi sembra abbastanza chiaro). Tuttavia, sarei felice se qualcuno potesse fornire una fonte che definisca chiaramente e inequivocabilmente cosa sia un'operazione supportata per i tipi di dati, o almeno definirla in termini migliori della mia (è quella definizione fornita in CLR? Non ho una copia ).

Il mio secondo punto sarà su come definiamo una coda prioritaria (che è la ragion d'essere dei cumuli binari). È increase_keyun'operazione necessaria per quel tipo di dati, ovvero per il suo corretto utilizzo?

Come puoi vedere, la mia prospettiva riguarda le definizioni. In realtà non fornisco una risposta alle tue domande, solo alcuni suggerimenti, quindi i miglioramenti sono ben accetti.


1
un caso d'uso di esempio può essere se voglio mantenere una coda prioritaria di oggetti basata sull'ultimo utilizzo (ad esempio in modo da poter eliminare facilmente gli oggetti utilizzati meno di recente). Posso usare un min-heap con la data dell'ultimo accesso come chiave. Se si accede a un oggetto, la sua chiave dovrà essere aumentata.
GatotPujo

Ottimo punto Il mio punto di vista è un po 'limitato, a quanto pare. Davvero, la risposta di @HendrikJan porta un'ottima spiegazione.
didierc
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.