Ordinamento per inserzione e algoritmi di ordinamento a bolle


87

Sto cercando di capire alcuni algoritmi di ordinamento, ma faccio fatica a vedere la differenza nell'algoritmo di ordinamento a bolle e di ordinamento per inserzione.

So che entrambi sono O (n 2 ), ma mi sembra che l'ordinamento a bolle faccia solo bolle il valore massimo dell'array verso l'alto per ogni passaggio, mentre l'ordinamento per inserzione affonda il valore più basso verso il basso ogni passaggio. Non stanno facendo la stessa identica cosa ma in direzioni diverse?

Per l'ordinamento per inserzione, il numero di confronti / scambi potenziali inizia da zero e aumenta ogni volta (cioè 0, 1, 2, 3, 4, ..., n) ma per l'ordinamento a bolle si verifica lo stesso comportamento, ma alla fine di l'ordinamento (cioè n, n-1, n-2, ... 0) perché il bubble sort non ha più bisogno di confrontarsi con gli ultimi elementi mentre vengono ordinati.

Nonostante tutto ciò, sembra un consenso sul fatto che l'ordinamento per inserzione sia migliore in generale. Qualcuno può dirmi perché?

Modifica: sono principalmente interessato alle differenze nel modo in cui funzionano gli algoritmi, non tanto alla loro efficienza o complessità asintotica.


1
Questo è ben documentato altrove: vedere, ad esempio, en.wikipedia.org/wiki/Sorting_algorithm . Piuttosto inutile duplicare qui e una buona risposta sarà espansiva.
Bathsheba

@Bathsheba 75 persone che hanno votato verso l'alto e 88k che hanno visto la domanda sembrano non essere d'accordo; )
parsecer

@parsecer: Ha! Ora dovrò rivedere le risposte. La risposta attuale con il voto più alto è utile; non sono sicuro degli altri. Ecco alcuni punti rep persi con il downvoting della risposta. L'affermazione "Ecco perché l'ordinamento per inserzione è più veloce dell'ordinamento a bolle" nella risposta accettata non è necessariamente vera.
Bathsheba

@Bathsheba Oh no
parsecer

Risposte:


41

Nell'ordinamento a bolle in ith iterazione hai ni-1 iterazioni interne (n ^ 2) / 2 in totale, ma nell'ordinamento per inserzione hai il massimo i iterazioni sull'i-esimo passaggio, ma in media i / 2, poiché puoi interrompere il ciclo interno in precedenza, dopo aver trovato la posizione corretta per l'elemento corrente. Quindi hai (somma da 0 a n) / 2 che è (n ^ 2) / 4 totale;

Ecco perché l'ordinamento per inserzione è più veloce dell'ordinamento a bolle.


2
La spiegazione dell'algoritmo è ovunque sul web, credo.
sasha.sochka

4
sì, ma sembra che l'OP ancora non
rilevi

15
Beh, puoi in qualche modo presumere che io capisca i fondamenti . Quello che volevo era un confronto, e questo è davvero abbastanza buono. Quindi l'idea è che mentre l'ordinamento per inserzione fa sì che l'elemento i-esimo affondi verso il basso e l'ordinamento a bolle lo fa gonfiare, l'ordinamento per inserzione non lo fa cadere fino in fondo, ma lo fa cadere nella giusta posizione in la sezione già ordinata. Quindi fa meno confronti / scambi. È giusto?
Migwell

2
Che cosa? "Quindi hai (somma da 0 an) / 2 che è (n ^ 2) / 4 totale" Questo richiede un po 'di spiegazione, per favore! 0 + 1 + 2 + 3 + 4 + 5 = 15; 15/2 = 7,5; 7,5 * 4 = 30; sqrt (30) = senza senso
John Smith

@ JohnSmith credo che ci sia un leggero errore nella risposta. La somma da 1 a n è n * (n + 1) / 2 in quanto è un numero triangolare. Cerca il numero triangolare per ulteriori spiegazioni. Quindi quello diviso per 2 è solo n * (n + 1) / 2.
CognizantApe

124

Ordinamento di inserzione

Dopo i iterazioni prima i elementi sono ordinati.

In ogni iterazione l'elemento successivo viene fatto scorrere attraverso la sezione ordinata fino a raggiungere il punto giusto:

sorted  | unsorted
1 3 5 8 | 4 6 7 9 2
1 3 4 5 8 | 6 7 9 2

Il 4 viene ribaltato nella sezione ordinata

Pseudocodice:

for i in 1 to n
    for j in i downto 2
        if array[j - 1] > array[j]
            swap(array[j - 1], array[j])
        else
            break

Bubble Sort

Dopo i iterazioni ultimi i elementi sono il più grande, e ordinato.

In ogni iterazione, passa al setaccio la sezione non ordinata per trovare il massimo.

unsorted  | biggest
3 1 5 4 2 | 6 7 8 9
1 3 4 2 | 5 6 7 8 9

Il 5 esce dalla sezione non ordinata

Pseudocodice:

for i in 1 to n
    for j in 1 to n - i
         if array[j] > array[j + 1]
             swap(array[j], array[j + 1])

Si noti che le implementazioni tipiche terminano in anticipo se non vengono effettuati scambi durante una delle iterazioni del ciclo esterno (poiché ciò significa che l'array è ordinato).

Differenza

Nell'ordinamento per inserzione gli elementi vengono ribaltati nella sezione ordinata, mentre nell'ordinamento a bolle i massimi vengono ribaltati fuori dalla sezione non ordinata.


10
Grazie, questo è molto chiaro! Penso che la cosa principale di cui avevo bisogno di evidenziare sia che l' istruzione break in Insertion Sort significa che può terminare ogni iterazione in anticipo: cioè quando ha trovato la sua posizione nella sezione ordinata. Il Bubble sort richiede che lo scambio continui fino a quando l'elemento più grande nella sezione non ordinata raggiunge la sezione ordinata, quindi non terminerà mai prima. Tuttavia è un riassunto fantastico, quindi +1
Migwell

4
Penso che questa dovrebbe essere la risposta migliore :)
Adelin

2
Più 1 per la chiarezza, il valore didattico e per le principali invarianti di ciclo di ogni algoritmo. Peccato che non contenga esplicitamente il confronto della complessità (espressa in funzione di n ), comunque la considero una risposta migliore di quella accettata, poiché da questa vedo la differenza.
Honza Zidek

Posso chiederti perché scambi il tuo articolo nel tuo pseudo codice di inserimento ad ogni passaggio? if (a [j-1]> a [j]) then a [j] = a [j-1] ELSE if (a [j-1] <e && a [j]> e) than a [j] = e; pausa; , dove e è l'elemento da ordinare. Con questa soluzione, non si scambiano gli elementi già ordinati, ma li si copia. Non vedo l'ora di avere una tua spiegazione, dato che sono un po 'confuso.
Karoly,

@Karoly, ho scelto la mia versione perché è più semplice. Il tuo è leggermente più veloce, è bene che tu lo indichi. Wikipedia descrive entrambe le versioni.
tom

16

Un'altra differenza, non ho visto qui:

Bubble sort ha 3 assegnazioni di valore per scambio : devi prima costruire una variabile temporanea per salvare il valore che vuoi spingere in avanti (n. 1), poi devi scrivere l'altra variabile di scambio nel punto in cui hai appena salvato il valore di (n. 2) e poi devi scrivere la tua variabile temporanea nell'altro punto (n. 3). Devi farlo per ogni punto - vuoi andare avanti - per ordinare la tua variabile nel punto corretto.

Con l'ordinamento per inserzione metti la tua variabile in ordine in una variabile temporanea e poi metti tutte le variabili davanti a quel punto 1 posto all'indietro, purché raggiungi il punto corretto per la tua variabile. Ciò fa 1 assegnazione di valore per spot . Alla fine scrivi la tua variabile temp nello spot.

Ciò rende anche molto meno assegnazioni di valore.

Questo non è il più forte vantaggio in termini di velocità, ma penso che possa essere menzionato.

Spero, mi sono espresso comprensibile, se no, mi dispiace, non sono un nativo della Gran Bretagna


1
"e poi metti tutte le variabili davanti a quel punto 1 posto all'indietro" - e questo non richiede anche un carico di compiti, per spostare i dati? (supponendo che i dati siano comunque memorizzati in modo contiguo, non in un elenco collegato)
Mark K Cowan

@MarkKCowan, sì, è lì che l'ordinamento per inserzione effettua l'assegnazione per "punto" come ha detto l'utente sopra. Fondamentalmente, l'ordinamento per inserzione può essere scritto con un compito nel ciclo interno, mentre bolleort ha 3 assegnazioni nel ciclo interno.
JSQuareD

9

Il vantaggio principale dell'ordinamento a inserimento è che è un algoritmo online. Non devi avere tutti i valori all'inizio. Questo potrebbe essere utile quando si tratta di dati provenienti dalla rete o da qualche sensore.

Ho la sensazione che questo sarebbe più veloce di altri n log(n)algoritmi convenzionali . Perché la complessità sarebbe, n*(n log(n))ad esempio, leggere / memorizzare ogni valore da stream ( O(n)) e quindi ordinare tutti i valori ( O(n log(n))) risultantiO(n^2 log(n))

Al contrario, utilizzando Inserisci ordinamento è necessario O(n)leggere i valori dallo stream e O(n)mettere il valore al posto corretto, quindi è O(n^2)solo. Un altro vantaggio è che non hai bisogno di buffer per memorizzare i valori, ma li ordini nella destinazione finale.


Se va bene che un attraversamento in ordine dei dati sia qualcosa di diverso dalla semplice scansione di un array, è possibile ordinare al volo in modo molto più efficiente. ad esempio, inserisci gli elementi in un albero binario man mano che li ricevi. Questo ti dà il O(n log(n))lavoro totale svolto per avere una raccolta ordinata in ogni fase del percorso. (Un attraversamento in ordine in qualsiasi punto è O(m)). Se hai solo bisogno di un risultato ordinato alla fine, ma vuoi sovrapporre il calcolo dell'ordinamento con il tempo di trasferimento dei dati, un Heap potrebbe essere buono. (E funziona sul posto, come l'ordinamento per inserimento).
Peter Cordes

Ad ogni modo, né l'ordinamento a bolle né l'ordinamento per inserzione sono ideali per questo con dimensioni del problema abbastanza grandi da far sì che la O(f(n))classe di complessità contenga più dei dettagli di implementazione e dei fattori costanti.
Peter Cordes

Correzione: un mucchio non va bene per questo. Svolge la maggior parte del lavoro di ordinamento mentre rimuovi gli elementi in ordine ordinato, motivo per cui la crescita è così economica. L'obiettivo qui è completare la maggior parte del lavoro prima che arrivi l'ultimo elemento.
Peter Cordes

Ad ogni modo, se hai bisogno di mantenere un array ordinato per gli ninserimenti, allora in realtà si riduce a quale algoritmo è migliore per ordinare un array quasi ordinato in cui c'è un elemento non ordinato in alto. Molti O(n log(n))algoritmi di ordinamento sono O(n)quasi ordinati, quindi non è vero che avresti bisogno di sum(M=1..n, O(M * log(M)) )lavoro. Sarebbe davvero O(n^2 log(n)), ma con la giusta scelta dell'algoritmo saranno O(n^2)un lavoro totale. Tuttavia, l'ordinamento per inserzione è il più efficiente per questo.
Peter Cordes

7

Bubble Sort non è online (non può ordinare un flusso di input senza sapere quanti elementi ci saranno) perché non tiene realmente traccia di un massimo globale degli elementi ordinati. Quando viene inserito un elemento, sarà necessario avviare la formazione di bolle dall'inizio


5

beh, l'ordinamento a bolle è migliore dell'ordinamento per inserzione solo quando qualcuno cerca i primi k elementi da un lungo elenco di numeri, ad esempio nel Bubble sort dopo k iterazioni otterrai i primi k elementi. Tuttavia, dopo k iterazioni nell'ordinamento per inserzione, assicura solo che quegli k elementi siano ordinati.


2

Sebbene entrambi gli ordinamenti siano O (N ^ 2). Le costanti nascoste sono molto più piccole nell'ordinamento per inserimento. Le costanti nascoste si riferiscono al numero effettivo di operazioni primitive eseguite.

Quando l'ordinamento per inserzione ha un tempo di esecuzione migliore?

  1. L'array è quasi ordinato: si noti che in questo caso l'ordinamento per inserzione esegue meno operazioni rispetto all'ordinamento a bolle.
  2. L'array è di dimensioni relativamente ridotte: l'ordinamento per inserzione sposta gli elementi, per inserire l'elemento corrente. Questo è solo meglio dell'ordinamento a bolle se il numero di elementi è basso.

Si noti che l'ordinamento per inserzione non è sempre migliore dell'ordinamento a bolle. Per ottenere il meglio da entrambi i mondi, è possibile utilizzare l'ordinamento per inserzione se l'array è di piccole dimensioni e probabilmente l'ordinamento (o quicksort) per gli array più grandi.


2
Se il numero di elementi non è piccolo, come sarebbe migliore il Bubble sort? La mia comprensione è che lo scorrimento in IS o lo scambio in BS dipenderà dal fatto che l'elemento confrontato sia maggiore (IS) o minore (BS) e non dal numero di elementi. Per favore correggimi se sbagliato.
Mustafa

1

Numero di scambi in ogni iterazione

  • L'ordinamento per inserzione esegue al massimo 1 scambio in ogni iterazione .
  • Bubble-sort esegue scambi da 0 a n in ogni iterazione.

Accesso e modifica della parte ordinata

  • L'ordinamento per inserzione accede (e cambia quando necessario) alla parte ordinata per trovare la posizione corretta di un numero in considerazione.
  • Quando è ottimizzato, Bubble-sort non accede a ciò che è già ordinato.

Online o no

  • L'ordinamento per inserzione è online. Ciò significa che l'ordinamento per inserimento richiede un input alla volta prima di essere posizionato nella posizione appropriata. Non deve solo confrontare adjacent-inputs.
  • Bubble-sort non è online. Non funziona un ingresso alla volta. Gestisce un gruppo di input (se non tutti) in ogni iterazione. Bubble-sort confronta e scambia soloadjacent-inputs in ogni iterazione.

0

Il Bubble sort è quasi inutile in tutte le circostanze. Nei casi d'uso in cui l'ordinamento per inserzione può avere troppi scambi, l'ordinamento per selezione può essere utilizzato perché garantisce meno di N volte di scambio. Poiché l'ordinamento per selezione è migliore dell'ordinamento a bolle, l'ordinamento a bolle non ha casi d'uso.


0

ordinamento di inserzione:

1.Nell'ordinamento per inserzione lo scambio non è richiesto.

2.la complessità temporale dell'ordinamento per inserzione è Ω (n) per il caso migliore e O (n ^ 2) per il caso peggiore.

3.less complesso rispetto al Bubble Sort.

4.esempio: inserire libri in biblioteca, disporre le carte.

Bubble sort: 1.Swapping richiesto nel Bubble Sort.

2.la complessità temporale del Bubble Sort è Ω (n) per il caso migliore e O (n ^ 2) per il caso peggiore.

3.più complesso rispetto all'ordinamento per inserzione.


1
Come mai lo scambio non è richiesto? Scambia gli elementi per mettere un elemento nella posizione corretta. E non direi che il bubble sort sia più complesso.
parsecer

-1

L'ordinamento per inserzione può essere ripreso come " Cerca l'elemento che dovrebbe essere in prima posizione (il minimo), crea un po 'di spazio spostando gli elementi successivi e mettilo in prima posizione. Bene. Ora guarda l'elemento che dovrebbe essere in seconda. ... "e così via ...

Il Bubble sort funziona in modo diverso, cosa che può essere ripresa come " Finché trovo due elementi adiacenti nell'ordine sbagliato, li scambio ".


Ciò aiuta con l'ordinamento per inserzione, ma la tua spiegazione del bubble sort non include i loop effettivi, quindi non posso davvero confrontarli. Anche l'ordinamento per inserzione ha effettivamente la regola Finché trovo due elementi adiacenti che sono nell'ordine sbagliato, li scambio , è il modo in cui funzionano i loop che è diverso.
Migwell

3
Non è questo tipo di selezione?
Harold
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.