/ / Come posso migliorare il mio codice Python sull'ordinamento dell'heap? - python, algoritmo, ordinamento, heapsort

Come posso migliorare il mio codice Python sull'ordinamento dell'heap? - python, algoritmo, ordinamento, heapsort

Ho provato a scrivere un programma di ordinamento per me stesso Leetcode 217. Contiene duplicati come di seguito piuttosto che usare l'ordinamento integrato Pythonmetodo. Il codice di leetcode dovrebbe accettare il metodo di ordinamento heap, ma per qualche motivo non lo so, sebbene il mio programma di ordinamento di heap funzioni bene, ho ancora ottenuto il rifiuto del runtime da Leetcode. Qualcuno può aiutarti?

Risolto, sotto il codice viene ri-modificato usando l'algoritmo Floyd per inizializzare l'heap e ha passato Leetcode

def heapsort(nums):

def swap(i, j):

nums[i], nums[j] = nums[j], nums[i]


def sift(start, size):

l = (start << 1) + 1 # Do not forget () for <<
r = l + 1
largest = start
if l <= size - 1 and nums[start] < nums[l]:
largest = l
if r <= size - 1 and nums[largest] < nums[r]:
largest = r
if largest != start:
swap(start, largest)
sift(largest, size)


size = len(nums)

# Initialize heap (Floyd Algorithm)
end = (size >> 1) - 1
while end >= 0:
sift(end, size)
end -= 1
swap(0, size - 1)
size -= 1

# Heapify recursively
while size > 1:
sift(0, size)
swap(0, size - 1)
size -= 1

risposte:

1 per risposta № 1

Il tuo codice fa troppo. Stai ricostruendo l'intero heap con ogni elemento che rimuovi, quindi quello che dovrebbe essere un algoritmo O (n log n) è invece O (n ^ 2).

In sostanza, il tuo codice sta facendo questo:

while array is not empty
rearrange array into a heap
extract the smallest item

Riorganizzare l'heap richiede, nel migliore dei casi, O (n) tempo. E estraendo il più piccolo prende O (log n). Quindi il tuo algoritmo è O (n ^ 2 + n log n).

In realtà, il tuo metodo per costruire l'heap dal basso verso l'alto è O (n log n) di per sé. Quindi l'algoritmo di ordinamento del cumulo è in realtà O ((n + 1) * (n log n)). In ogni caso, è un algoritmo altamente sub-ottimale.

L'idea dietro l'ordinamento dell'heap consiste nel disporre l'array in un heap Una volta. Questa è un'operazione O (n). L'algoritmo è piuttosto semplice:

for i = heap.length/2 downto 1
siftDown(i)

Questo è chiamato L'algoritmo di Floyd, dopo il suo inventore.

Si noti che iniziamo nel mezzo dell'array e setacciamo giù. L'idea è che gli ultimi n / 2 oggetti sono nodi foglia, quindi non possono "t passare" in ogni caso, iniziando da n / 2 e lavorando all'indietro, possiamo rendere l'intero array in O (n).

Dopo che l'array è organizzato in un heap, facciamo quanto segue:

while heap is not empty
output the item at heap[0]
move the item at the end of the heap to heap[0]
reduce the count of items by 1
siftDown(0)

L'elemento nell'heap [0] è l'elemento più piccolorimanendo nell'heap, quindi l'output. Quindi, non è necessario ricostruire l'intero heap, è sufficiente prendere l'ultimo elemento nell'heap, posizionarlo in alto e spostarlo in posizione, mentre il resto dello heap rimane valido.

Apportare quelle modifiche dovrebbe ridurre la corsatempo, anche se non so se questo renderà il tuo codice accettabile. C'è un altro modo per verificare i duplicati. Richiede O (n) spazio extra, ma è più veloce dell'ordinamento.

L'idea è di creare una tabella hash e poi andareattraverso l'array, controllando se l'elemento si trova nella tabella hash. In caso contrario, aggiungilo. Se è già nella tabella, allora è un duplicato. Come ha sottolineato Harold, Python ha un impostato tipo che rende questo genere di cose facile da fare.


0 per risposta № 2

A proposito di specie di heap, prendi in considerazione heapq modulo python. Esiste proprio per questo scopo: fornire un'implementazione dell'algoritmo della coda heap. Non è progettato in modo non molto conveniente, ma ci sono a portata di mano wrapper - puoi google tu stesso.

A proposito di trovare duplicati, qualsiasi n log(n) l'algoritmo di ordinamento non dovrebbe essere abbastanza efficiente. Dai un'occhiata al pitone impostato incorporato!