2009-11-16 14 views
22

Come posso implementare in modo efficiente una struttura di dati dell'elenco in cui posso avere 2 viste alla testa e alla fine dell'elenco, che puntano sempre a una coda di una lista senza chiamate costose da invertire. cioè:Efficiente coda in Haskell

start x = [] 
end x = reverse start -- [] 
start1 = [1,2,3] ++ start 
end start1 -- [3,2,1] 

finale dovrebbe essere in grado di farlo senza invocare 'inverso', ma semplicemente guardando la lista data dal punto di vista della lista sia in senso inverso automaticamente. Lo stesso dovrebbe valere se creo nuovi elenchi dalle concatenazioni per iniziare.

+1

In Haskell non è possibile modificare i valori. 'start' sarà sempre la lista vuota, e' end' sarà sempre il 'reverse' di quello (la lista vuota). Se vuoi mantenere lo stato, dovresti guardare la monade di stato. Correzione –

+1

: per aggiornamento intendo rebind. – TheOne

+1

@Absolute: quello che tu chiami non cambia la verità ultima che non puoi * cambiare * cose (nonostante 'monade IO') in Haskell. Non puoi riassociare le cose. –

risposta

34

Si può sempre usare appena Data.Sequence.

Un'implementazione ben nota di una coda puramente funzionale consiste nell'utilizzare due elenchi. Uno per l'accodamento e l'altro per la rimozione. Enqueue sarebbe semplicemente contro con l'elenco di accodamento. Dequeue prende la testa dell'elenco di dequeue. Quando l'elenco di dequotazione è vuoto, riempirlo invertendo la lista di accodamento. Vedi Chris Okasaki's Purely Functional Datastructures.

Anche se questa implementazione utilizza reverse, il costo di ammortamento di questo è insignificante in modo asintotico. Funziona in modo che per ogni acconto, si incorre in un debito di tempo di Θ (1) per la ricarica della lista di dequeue. Il tempo atteso di una coda di attesa è quindi il doppio di un accodamento. Questo è un fattore costante, quindi il costo di entrambe le operazioni è Θ (1).

+14

Insignificante * solo * se usato effimero. Se la tua applicazione dipende dalla persistenza, allora è del tutto possibile imbattersi in quel caso O (n) ogni volta che accedi alla tua coda. – Juliet

+4

@Juliet Con l'uso della pigrizia e della memoizzazione, il limite ammortizzato è ancora O (1) pur mantenendo la persistenza – Yuhta

+1

@Yuhta puoi mostrare un esempio usando la pigrizia e la memoizzazione? – CMCDragonkai

1

Non sono realmente un utente Haskell, ma ho trovato a blog post che dichiara di descrivere una coda Haskell che può essere utilizzata in tempo costante ammortizzato. Si basa su un progetto dell'ottima struttura dati puramente funzionale di Chris Okasaki.

5

Is Data.Dequeue Cosa stai cercando?

(Non deve reverse ma è possibile aggiungerlo abbastanza facilmente e inviare una patch per l'autore.)

+5

Sono consapevole della libreria, voglio solo implementarla io stesso come un divertente esperimento mentale. – TheOne

+0

Oppure puoi usare il modulo 'Data.Sequence' che è già nella libreria standard – newacct

+0

Oppure ... possono implementarlo come un divertente esperimento di pensiero, come hanno stabilito che volevano fare. E non c'è niente di sbagliato in questo. – semicolon