Qual è l'algoritmo di ordinamento a spazio costante più efficiente?


19

Sto cercando un algoritmo di ordinamento per array int che non alloca alcun byte diverso dalle dimensioni dell'array ed è limitato a due istruzioni:

  1. SWAP: scambia l'indice successivo con quello attuale;

  2. SPOSTA: sposta il cursore sull'indice +1 o -1;

Cioè, non è possibile scambiare indici non vicini, né scambiare l'indice 100, dopo aver appena scambiato l'indice 10. Qual è l'algoritmo più efficiente, ovvero quello che utilizza il minor numero di mosse totali?


13
Non così strano, è una macchina fisica che ordinerà un elenco di carrelli incollati su un nastro che viene arrotolato. La macchina può solo spostare il nastro in avanti o indietro, e può scambiare solo carte vicine, di corsa. Nel mondo reale non puoi teletrasportarti in giro, quindi quelle sono le restrizioni ...
MaiaVictor

2
Quindi, quando dici che vuoi un algoritmo che non alloca alcun byte diverso dalle dimensioni dell'array , immagino che ti riferisci solo alla memoria degli elementi, giusto? Posso ancora allocare contatori e simili?
Darkhogg,

5
Oh certo. Ovviamente. È possibile allocare alcune strutture aggiuntive. È anche possibile allocare l'intero array ed eseguire un calcolo molto pesante e che conta come costo 0. L'unica cosa che devi minimizzare è il numero di SWAP / MOVE dell'attuale macchina fisica, perché è lento. L'ordinamento a bolle è il migliore che ho potuto inventare, ma ho immaginato che ci dovrebbero essere opzioni migliori.
MaiaVictor

1
Non penso che esista un tale algoritmo. Senza alcuna memoria aggiuntiva, non avrete alcun modo per memorizzare qualsiasi stato di controllo.
Raffaello

1
@svrm: sì, quindi con RAM illimitata e la possibilità di copiare il nastro nella RAM e fare un calcolo arbitrario su di esso gratuitamente, l'algoritmo "prova tutto e applica il meglio" è ottimale in termini di numero di spostamenti del nastro. È improbabile che sia pratico, ma è perché in pratica il tempo di esecuzione sarebbe di miliardi di anni, non 0 ;-) Se costa N si sposta per copiare un nastro di lunghezza N in RAM, la forza bruta ingenua potrebbe non essere ottimale ma è all'interno di N di ottimale. Ma nulla di tutto ciò è specifico del tuo problema: molti problemi, se dichiarati in questo modo, potrebbero essere risolti "offline" usando un algoritmo fasullo.
Steve Jessop,

Risposte:



4

Il numero di scambi di elementi adiacenti necessari per ordinare un array è uguale al numero di inversioni nell'array. Con n elementi in totale, ci sono al massimo n * (n-1) / 2 inversioni, quindi l'ordinamento a bolle fornisce il numero di swap asintoticamente ottimale in questo modello.


In realtà, l'ordinamento a bolle fornirà esattamente il numero ottimale di swap. Tuttavia, per ogni permutazione ci sono diversi modi per fare il numero ottimale di swap, e non è ovvio quale si riduce il numero totale di mosse. (Per bolla ordinata intendo "selezionare il più grande non ordinato e spostarlo alla fine dell'ordinato")
Peter Kravchuk

4

O(n2)

+

L'algoritmo che non utilizza un flag booleano per sapere se abbiamo scambiato qualche elemento o meno, è riportato di seguito (il trucco per mantenere le informazioni nello stato della macchina, piuttosto che nella memoria):

Start:
    Do until we are not at the leftmost position (Op 4)
        move left (Op 2b)

Check:
    If we are at rightmost position (Op 3)
        goto Finished:
    If current value is larger than next value (Op 5)
        goto Unfinished:
    move right (Op 2a)
    Repeat Check:

Unfinished:
    If we are at rightmost position (Op 3)
        goto Start:
    If current value is larger than next value (Op 5)
        swap the elements (Op 1) and move right (Op 2a)
    Repeat Unfinished:

Finished:
    The list is sorted now, output it.

La soluzione di Eric Lippert, anche la specie gnome , funziona, perché fondamentalmente è una specie di bolla a due vie.


Che dire dell'ordinamento per inserzione?
Darkhogg,

L'ordinamento delle bolle necessita di almeno due contatori di loop che sono già più di quanto consentito.
Raffaello

1
No, puoi andare a sinistra e a destra, quindi a destra a sinistra, fino a quando non ci sono cambiamenti (che è un massimo di n volte) senza usare il contatore. Non c'è nemmeno bisogno di spazio extra per una bandiera booleana da notare se c'è un cambiamento. Se si verifica una modifica, si passa semplicemente a un'altra subroutine che fa lo stesso, tranne per il fatto che si tratta di un'altra subroutine.
Shreesh,

1
E, naturalmente, suppongo che tu possa leggere in bianco ad entrambe le estremità in modo da poter sapere che è l'inizio o la fine della lista. Inoltre, presumo che leggiamo sia l'elemento corrente sia quello successivo per sapere se dobbiamo scambiare.
Shreesh,

1
Oppure, se modifichiamo lo scambio operatore come "scambio se non in ordine crescente".
Shreesh,
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.