Capire la Ricorsione di mergesort

Più del mergesort implementazioni vedo sono simili a questo. introduzione ad algoritmi di prenotare online implentations cercare. Il mio ricorsione braciole di non andare molto oltre che pasticciano con la generazione di Fibonacci (che era abbastanza semplice) quindi forse la più ricorsioni che soffia la mia mente, ma non riesco nemmeno il passaggio attraverso il codice e capire cosa sta succedendo, anche prima che mi ha colpito anche la funzione di unione.

Come è passato attraverso questo? C’è qualche strategia o la lettura mi dovrebbero sottoporsi a comprendere meglio il processo qui?

void mergesort(int *a, int*b, int low, int high)
{
    int pivot;
    if(low<high)
    {
        pivot=(low+high)/2;
        mergesort(a,b,low,pivot);
        mergesort(a,b,pivot+1,high);
        merge(a,b,low,pivot,high);
    }
}

e l’unione(anche se francamente io sono mentalmente bloccato prima ancora di scendere a questa parte)

void merge(int *a, int *b, int low, int pivot, int high)
{
    int h,i,j,k;
    h=low;
    i=low;
    j=pivot+1;

    while((h<=pivot)&&(j<=high))
    {
        if(a[h]<=a[j])
        {
            b[i]=a[h];
            h++;
        }
        else
        {
            b[i]=a[j];
            j++;
        }
        i++;
    }
    if(h>pivot)
    {
        for(k=j; k<=high; k++)
        {
            b[i]=a[k];
            i++;
        }
    }
    else
    {
        for(k=h; k<=pivot; k++)
        {
            b[i]=a[k];
            i++;
        }
    }
    for(k=low; k<=high; k++) a[k]=b[k];
}
InformationsquelleAutor 2c2c | 2013-09-28



9 Replies
  1. 14

    Penso che la “specie” nome di funzione MergeSort è un po ‘ un termine improprio, in realtà dovrebbe essere chiamato “dividere”.

    Qui è una visualizzazione dell’algoritmo in termini di processo.

    Capire la Ricorsione di mergesort

    Ogni volta che la funzione effettui, è lavorare su una più piccola suddivisione dell’array di input, partendo da sinistra, e la metà di esso. Ogni volta che la funzione ritorna dalla ricorsione, continuerà su e iniziare a lavorare sulla metà destra, o recurse di nuovo e lavorare su più della metà.

    Come questo

    [************************]mergesort
    [************]mergesort(lo,mid)
    [******]mergesort(lo,mid)
    [***]mergesort(lo,mid)
    [**]mergesort(lo,mid)
     [**]mergesort(mid+1,hi)
    [***]merge
       [***]mergesort(mid+1,hi)
       [**]mergesort*(lo,mid)
        [**]mergesort(mid+1,hi)
       [***]merge
    [******]merge
          [******]mergesort(mid+1,hi)
          [***]mergesort(lo,mid)
          [**]mergesort(lo,mid)
           [**]mergesort(mid+1,hi)
          [***]merge
             [***]mergesort(mid+1,hi)
             [**]mergesort(lo,mid)
               [**]mergesort(mid+1,hi)
             [***]merge
          [******]merge
    [************]merge
                [************]mergesort(mid+1,hi)
                [******]mergesort(lo,mid)
                [***]mergesort(lo,mid)
                [**]mergesort(lo,mid)
                 [**]mergesort(mid+1,hi)
                [***]merge
                   [***]mergesort(mid+1,hi)
                   [**]mergesort(lo,mid)
                     [**]mergesort(mid+1,hi)
                   [***]merge
                [******]merge
                      [******]mergesort(mid+1,hi)
                      [***]mergesort(lo,mid)
                      [**]mergesort*(lo,mid)
                        [**]mergesort(mid+1,hi)
                      [***]merge
                         [***]mergesort(mid+1,hi)    
                         [**]mergesort(lo,mid)
                          [**]mergesort(mid+1,hi)
                         [***]merge
                      [******]merge
                [************]merge
    [************************]merge
    
  2. 19

    MERGE SORT:

    1) Dividere l’array a metà

    2) Ordina la metà sinistra

    3) Ordinare la metà destra

    4) Unisci le due metà insieme

    Capire la Ricorsione di mergesort

    Capire la Ricorsione di mergesort

  3. 8

    Una cosa ovvia da fare sarebbe quella di provare questo merge sort su un piccolo array, dicono dimensione 8 (potenza di 2 è conveniente qui), su carta. Fingi di essere un computer di eseguire il codice, e vedere se inizia a diventare un po ‘ più chiaro.

    La tua domanda è un po ‘ ambigua, perché non si spiega che cosa si confondono, ma suona come si sta cercando di srotolare le chiamate ricorsive nella tua testa. Che può o non può essere una buona cosa, ma penso che può facilmente portare a mangiare troppo in testa in una sola volta. Invece di cercare di rintracciare il codice dall’inizio alla fine, per vedere se si può capire il concetto astratto. Merge sort:

    1. Divide l’array a metà
    2. Ordina la metà sinistra
    3. Ordina la metà destra
    4. Unisce le due metà insieme

    (1) dovrebbe essere abbastanza ovvio e intuitivo per l’utente. Per il punto (2) l’idea chiave è questa, la metà sinistra di un array… è un array. Ipotizzando che il merge sort opere, dovrebbe essere in grado di ordinare la metà sinistra della matrice. Giusto? Punto (4) è in realtà una bella parte intuitiva di algoritmo. Un esempio dovrebbe rendere banale:

    at the start
    left: [1, 3, 5], right: [2, 4, 6, 7], out: []
    
    after step 1
    left: [3, 5], right: [2, 4, 6, 7], out: [1]
    
    after step 2
    left: [3, 5], right: [4, 6, 7], out: [1, 2]
    
    after step 3
    left: [5], right: [4, 6, 7], out: [1, 2, 3]
    
    after step 4
    left: [5], right: [6, 7], out: [1, 2, 3, 4]
    
    after step 5
    left: [], right: [6, 7], out: [1, 2, 3, 4, 5]
    
    after step 6
    left: [], right: [7], out: [1, 2, 3, 4, 5, 6]
    
    at the end
    left: [], right: [], out: [1, 2, 3, 4, 5, 6, 7]
    

    Quindi, supponendo che si capisce (1) e (4), un altro modo di pensare il merge sort sarebbe questo. Immaginare qualcun altro ha scritto mergesort() e sei sicuro che funziona. Quindi si potrebbe utilizzare l’attuazione di mergesort() per scrivere:

    sort(myArray)
    {
        leftHalf = myArray.subArray(0, myArray.Length/2);
        rightHalf = myArray.subArray(myArray.Length/2 + 1, myArray.Length - 1);
    
        sortedLeftHalf = mergesort(leftHalf);
        sortedRightHalf = mergesort(rightHalf);
    
        sortedArray = merge(sortedLeftHalf, sortedRightHalf);
    }
    

    Nota che sort non utilizzare la ricorsione. Dice solo “ordinamento metà e poi unirli”. Se hai capito l’esempio di unione di cui sopra allora speriamo che si vede intuitivamente che questo sort funzione sembra di fare quello che dice… o quasi.

    Ora, se si guarda con più attenzione… sort() sembra molto più esattamente come mergesort()! Ecco perché è mergesort() (tranne che non ha base dei casi, perché non è ricorsiva!).

    Ma è così che mi piace pensare di funzioni ricorsive, si supponga che la funzione è attiva quando viene chiamata. Trattare come una scatola nera che ciò di cui hai bisogno. Quando si fanno ipotesi, per capire come riempire quella scatola nera è spesso facile. Per un dato input, si può rompere giù in piccoli ingressi per nutrire la vostra scatola nera? Dopo aver risolto questo, l’unica cosa che rimane è la manipolazione della base di casi all’inizio della sua funzione (che sono i casi in cui non è necessario apportare eventuali chiamate ricorsive. Per esempio, mergesort([]) restituisce un array vuoto; non effettuare una chiamata ricorsiva per mergesort()).

    Infine, questo è un po ‘ astratto, ma un buon modo per capire la ricorsione è in realtà per scrivere le prove matematiche utilizzando l’induzione. La stessa strategia utilizzata per la scrittura di una dimostrazione per induzione è utilizzato per scrivere una funzione ricorsiva:

    Matematica prova:

    • Mostra il reclamo è vero per la base casi
    • Per scontato che è vero per gli ingressi più piccolo di alcuni n
    • Utilizzare questa ipotesi per dimostrare che è ancora vero per un input di dimensione n

    Funzione ricorsiva:

    • Gestire la base casi
    • Si supponga che la funzione ricorsiva opere degli ingressi più piccolo di alcuni n
    • Utilizzare questa ipotesi per gestire un input di dimensione n
  4. 6

    Riguardanti la ricorsione parte del merge sort, ho trovato questo pagina essere molto molto utile. È possibile seguire il codice viene eseguito. Esso mostra ciò che viene eseguito per primo, e quello successivo.

    Tom

    • Anche se questa risposta porta ad un’altra pagina, la pagina di destinazione può essere qualcosa che molte persone sono pazzi per ….
    • Questo video di youtube ( youtube.com/watch?v=i56B0xN7jSc ) è un’altra fonte per trovare una rappresentazione visiva di merge sort
  5. 4

    il mergesort() semplicemente divide l’array in due metà fino a quando il if condizione non riesce che è low < high. Come si chiama mergesort() due volte : una con low per pivot e la seconda con pivot+1 per high, questo dividere il sub array ancor più ulteriormente.

    Facciamo un esempio :

    a[] = {9,7,2,5,6,3,4}
    pivot = 0+6/2 (which will be 3)
    => first mergesort will recurse with array {9,7,2} : Left Array
    => second will pass the array {5,6,3,4} : Right Array
    

    Verrà ripetuta fino a quando si dispone di 1 elemento in ogni left nonché right array.
    Alla fine avrete qualcosa di simile a questo :

    L : {9} {7} {2} R : {5} {6} {3} {4} (each L and R will have further sub L and R)
    => which on call to merge will become
    
    L(L{7,9} R{2}) : R(L{5,6} R{3,4})
    As you can see that each sub array are getting sorted in the merge function.
    
    => on next call to merge the next L and R sub arrays will get in order
    L{2,7,9} : R{3,4,5,6}
    
    Now both L and R sub array are sorted within
    On last call to merge they'll be merged in order
    
    Final Array would be sorted => {2,3,4,5,6,7,9}
    

    Vedere la fusione procedura descritta nella risposta data da @roliu

  6. 3

    Le mie scuse se questo è stato risposto in questo modo. Riconosco che questo è solo uno schizzo, piuttosto che una profonda spiegazione.

    Mentre non è ovvio per vedere come effettivamente il codice di mappe per la ricorsione, sono stato in grado di capire la ricorsione in un generale senso in questo modo.

    Fare un esempio indifferenziati set {2,9,7,5} come input. Il merge_sort algoritmo è denotato da “ms” per brevità di seguito. Quindi siamo in grado di tracciare il funzionamento come:

    passo 1: ms( ms ms(2),ms(9) ), ms( ms(7),ms(5) ) )

    passo 2: ms( ms({2},{9}), ms({7},{5}) )

    passo 3: ms( {2,9}, {5,7} )

    passo 4: {2,5,7,9}

    È importante notare che merge_sort di un singoletto (come {2}) è semplicemente il singoletto (ms(2) = {2}), in modo che al livello più profondo della ricorsione abbiamo ottenuto la nostra prima risposta. Le restanti risposte poi cadere come domino interni ricorsioni finitura e sono unite insieme.

    Parte del genio dell’algoritmo è il modo in cui si costruisce la formula ricorsiva di fase 1 automaticamente attraverso la sua costruzione. Ciò che mi ha aiutato è stato l’esercizio di pensare come trasformare il punto 1 di cui sopra statica formula a un generale di ricorsione.

  7. 0

    processo a suddividere il problema in sottoproblemi
    Esempio, vi aiuterà a capire la ricorsione. int A[]={numero di elemento in corto.}, int p=0; (amante dell’indice). int r= A. length – 1;(indice più Alto).

    class DivideConqure1 {
    void devide(int A[], int p, int r) {
        if (p < r) {
            int q = (p + r) /2; //divide problem into sub problems.
            devide(A, p, q);   //divide left problem into sub problems
            devide(A, q + 1, r); //divide right problem into sub problems
            merger(A, p, q, r);  //merger the sub problem
        }
    }
    
    void merger(int A[], int p, int q, int r) {
        int L[] = new int[q - p + 1];
        int R[] = new int[r - q + 0];
    
        int a1 = 0;
        int b1 = 0;
        for (int i = p; i <= q; i++) {  //store left sub problem in Left temp
            L[a1] = A[i];
            a1++;
        }
        for (int i = q + 1; i <= r; i++) { //store left sub problem in right temp
            R[b1] = A[i];
            b1++;
        }
        int a = 0;
        int b = 0; 
        int c = 0;
        for (int i = p; i < r; i++) {
            if (a < L.length && b < R.length) {
                c = i + 1;
                if (L[a] <= R[b]) { //compare left element<= right element
                    A[i] = L[a];
                    a++;
                } else {
                    A[i] = R[b];
                    b++;
                }
            }
        }
        if (a < L.length)
            for (int i = a; i < L.length; i++) {
                A[c] = L[i];  //store remaining element in Left temp into main problem 
                c++;
            }
        if (b < R.length)
            for (int i = b; i < R.length; i++) {
                A[c] = R[i];  //store remaining element in right temp into main problem 
                c++;
            }
    }
    
  8. 0

    So che questa è una vecchia questione, ma ha voluto lanciare il mio pensiero di ciò che mi ha aiutato a capire il merge sort.

    Ci sono due grandi parti di merge sort

    1. Suddivisione della matrice in blocchi più piccoli (dividendo)
    2. Unione di matrice insieme (la conquista)

    Il ruolo di recurison è semplicemente il dividendo porzione.

    Penso che quello che confonde la maggior parte delle persone è che essi pensano che ci sia un sacco di logica la scissione e la determinazione per dividere, ma la maggior parte dell’attuale logica di ordinamento accade sul unione. La ricorsione è lì semplicemente per dividere e fare la prima metà e la seconda metà è in realtà solo un loop, la copia di cose.

    Vedo alcune risposte che parlare di perni, ma mi sento di raccomandare di non associare la parola “pivot” con il merge sort perché è un modo semplice per confondere il merge sort con quicksort (che è fortemente dipendente per quanto riguarda la scelta di un “pivot”). Entrambi sono del “divide et impera” algoritmi. Per il merge sort la divisione avviene sempre in mezzo, mentre per il quicksort si può essere abili con la divisione di scelta di un ottimale pivot.

  9. 0

    Quando si chiama il metodo ricorsivo non esegue la funzione reale al tempo stesso stack in memoria dello stack. E quando la condizione non è soddisfatta poi va alla riga successiva.

    Considera che questa è la matrice:

    int a[] = {10,12,9,13,8,7,11,5};
    

    Così il metodo merge sort di lavoro come di seguito:

    mergeSort(arr a, arr empty, 0 , 7);
    mergeSort(arr a, arr empty, 0, 3);
    mergeSort(arr a, arr empty,2,3);
    mergeSort(arr a, arr empty, 0, 1);
    
    after this `(low + high) /2 == 0` so it will come out of first calling and going to next:
    
        mergeSort(arr a, arr empty, 0+1,1);
    
    for this also `(low + high) /2 == 0` so it will come out of 2nd calling also and call:
    
        merger(arr a, arr empty,0,0,1);
        merger(arr a, arr empty,0,3,1);
        .
        .
        So on
    

    Modo a tutti di ordinare i valori di archivio nel vuoto arr.
    Potrebbe aiutare a capire come funzione ricorsiva opere

Lascia un commento