Quale algoritmo usa l'ordinamento?


24

Devo aggiungere un singolo numero intero a un elenco già ordinato, in modo che vada nel posto giusto. Il mio primo pensiero è stato qualcosa di simile

(sort (cons newelt list) #'<)

Tuttavia, dato che listè già stato ordinato, è davvero necessario solo un inserimento, il che significa che questa soluzione potrebbe essere orribilmente inadatta a seconda dell'algoritmo utilizzato da sort.

Quindi, qual è l'algoritmo che sortutilizza?

Sarebbe meglio fare qualcosa di simile al seguente?

(let ((tail list))
  ;; The first element is never less-than
  (while (and tail (< newelt (cadr tail)))
    (setq tail (cdr tail)))
  (setcdr tail (cons newelt (cdr tail)))
  list)

1
Userei un heap binario (es. Heap.el ), se fosse un'operazione frequente nel mio codice.
lunaryorn,

Sia Biniziale già ordinato liste Ae Cinizialmente liste vuote. Dividi Bin due parti B1, B2di lunghezze me mo m+1e m, rispetto neweltal primo elemento di B2. Se neweltsi estende Aalla sua destra con B1e si sostituisce Bcon B2, altrimenti si estende Calla sua sinistra con B2e si sostituisce Bcon B1. Dopo O(log n)tali passaggi non viene lasciato nulla B. Quindi Acontiene le cose ≤ newelte Cquelle > newelt, e la concatenazione produce l'elenco ordinato esteso. Ci scusiamo per il e-lisplinguaggio non molto simile.
jfbu,

Risposte:


26

Se hai installato il codice sorgente di Emacs, puoi trovare il codice sorgente sortcon M-x find-function.

Lì puoi vedere che sortesegue un ordinamento di unione. Verifica la lunghezza dell'elenco, divide l'elenco a metà, ordina le parti "anteriore" e "posteriore" separatamente attraverso la ricorsione, quindi unisce le due.

Quanto alla tua implementazione sarebbe più veloce - misurala! È più efficiente in teoria (O (n) vs O (n log n)), ma sortha il vantaggio di essere scritto in C, quindi il risultato potrebbe andare in entrambi i modi. (Ovviamente, non dimenticare di compilare byte la tua funzione.)


@Malabarba Per la cronaca, su quale scala di lunghezze lo hai provato?
T. Verron,

8
Testato 1000 volte inserendo un numero casuale in un elenco di 1000 numeri casuali (tutti pregenerati). Il metodo manuale è stato 6 volte più veloce.
Malabarba,
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.