Esercizio 14k-esimo elemento più piccolo con uno heap
In questa pagina 6
Testo (esempio di tema d'esame, seconda parte, esercizio 1, 5 punti). Progettare un algoritmo che calcola il -esimo elemento più piccolo di un insieme di interi distinti, in tempo e senza ricorrere all'ordinamento.
Idea
Il termine suggerisce una costruzione bottom-up di uno heap, che costa ; il termine suggerisce operazioni di removeMin, ciascuna . Il minimo estratto per -esimo è il -esimo più piccolo (vedi HeapAlbero binario completo e sua altezza floor(log2 n); heap = albero completo con heap-order property; proprietà (radice minima, cammini non decrescenti); rappresentazione su array con level numbering; insert con up-heap bubbling, removeMin con down-heap bubbling, rimozione di una entry qualsiasi; invarianti e costi Theta(log n); esempio svolto.Heap → e Costruzione di uno heapCostruire uno heap da un array di n entry: approccio top-down con n-1 insert, Theta(n log n); approccio bottom-up con down-heap dalle foglie verso la radice, Theta(n), con dimostrazione della somma; esempi svolti, in loco; unione di due alberi con heap-order.Costruzione di uno heap →). Ordinare tutto l'insieme costerebbe , peggio quando è piccolo.
Algoritmo
Algoritmo kEsimoMinimo(A, n, k)
Input: array A[1..n] di interi distinti, intero 1 <= k <= n
Output: il k-esimo elemento più piccolo di A
P <- A (lavoro in loco sull'array)
for j <- floor(n/2) downto 1 do (costruzione bottom-up di un min-heap)
down-heap bubbling a partire da P[j]
last <- n
for t <- 1 to k - 1 do
P[1] <- P[last]; last <- last - 1 (removeMin, scartando il minimo)
down-heap bubbling a partire da P[1]
return P[1] (il k-esimo minimo: la radice)L'ultima operazione non serve completarla: dopo rimozioni la radice dello heap è il -esimo più piccolo (equivalentemente, si può fare removeMin() volte e restituire l'ultimo valore estratto).
Correttezza. Lo heap contiene sempre gli elementi non ancora scartati. Dopo la costruzione la radice è il minimo (1° più piccolo). A ogni removeMin si toglie il minimo corrente, quindi dopo rimozioni sono stati tolti i elementi più piccoli e la radice è il -esimo. Dopo rimozioni la radice è il -esimo.
Esempio
, .
- Bottom-up (): : ; : ; : (il scende prima scambiandosi con , poi con ).
- Rimozione 1 (si scarta ): in radice, .
- Rimozione 2 (si scarta ): in radice, .
- La radice è : il terzo più piccolo, in accordo con l'ordinamento .
Complessità
- Costruzione bottom-up: (somma dei costi per livello, vedi Costruzione di uno heapCostruire uno heap da un array di n entry: approccio top-down con n-1 insert, Theta(n log n); approccio bottom-up con down-heap dalle foglie verso la radice, Theta(n), con dimostrazione della somma; esempi svolti, in loco; unione di due alberi con heap-order.Costruzione di uno heap →).
- rimozioni: ciascuna (altezza dello heap ): .
Totale: . Per è lineare. Se è vicino a non conviene rispetto all'ordinamento ( in entrambi i casi), ma la richiesta dell'esercizio è proprio questo limite.
Varianti
Con una coda con priorità su array non ordinato la costruzione è banale ma ogni removeMin costa : . Con lista ordinata si paga per ordinare. Lo heap bilancia i costi (vedi Code con prioritàEntry chiave-valore; ADT coda con priorità (insert, min, removeMin) con chiave minima = priorità massima; esempio di esecuzione; applicazioni; implementazioni con lista non ordinata e ordinata e relativi costi; ordinamento tramite coda con priorità.Code con priorità →).
Errori comuni
- Costruire lo heap con
insert(top-down): , che viola il limite richiesto. - Errore di uno: se si fanno estrazioni e si restituisce la radice dopo l'ultima, si ottiene il -esimo; vale o il valore estratto alla -esima estrazione, o la radice dopo estrazioni.
- Usare un max-heap senza adattare (con un max-heap si cerca il -esimo più grande).
- Dimenticare che gli elementi sono distinti: con ripetizioni "-esimo più piccolo" va ridefinito.
Versione ripasso
Testo. -esimo elemento più piccolo di interi distinti in , senza ordinare.
- Idea: ⇒ heap bottom-up; ⇒
removeMin(vedi Costruzione di uno heapCostruire uno heap da un array di n entry: approccio top-down con n-1 insert, Theta(n log n); approccio bottom-up con down-heap dalle foglie verso la radice, Theta(n), con dimostrazione della somma; esempi svolti, in loco; unione di due alberi con heap-order.Costruzione di uno heap →). - Algoritmo: min-heap bottom-up in ; rimozioni del minimo (, , down-heap); la radice è il -esimo minimo.
- Esempio: , : heap ; dopo due rimozioni la radice è .
- Complessità: (vedi HeapAlbero binario completo e sua altezza floor(log2 n); heap = albero completo con heap-order property; proprietà (radice minima, cammini non decrescenti); rappresentazione su array con level numbering; insert con up-heap bubbling, removeMin con down-heap bubbling, rimozione di una entry qualsiasi; invarianti e costi Theta(log n); esempio svolto.Heap →).
- Codice:
for j <- floor(n/2) downto 1: down-heap(P, j); ripeti volteP[1] <- P[last]; last--; down-heap(P, 1);return P[1]. Esempio : heap , dopo rimozioni la radice è . - Errori: costruzione con
insert(); sbagliare di uno; max-heap per il -esimo minimo.