简体   繁体   中英

Trouble understanding a specific C implementation of Merge Sort

I'm trying to follow this code step by step but still I can't understand certain steps it's taking.

void merge (int *a, int n, int m) {
    int i, j, k;
    int *x = malloc(n * sizeof (int));
    for (i = 0, j = m, k = 0; k < n; k++) {
        x[k] = j == n      ? a[i++]
             : i == m      ? a[j++]
             : a[j] < a[i] ? a[j++]
             :               a[i++];
    }
    for (i = 0; i < n; i++) {
        a[i] = x[i];
    }
    free(x);
}

void merge_sort (int *a, int n) {
    if (n < 2)
        return;
    int m = n / 2;
    merge_sort(a, m);
    merge_sort(a + m, n - m);
    merge(a, n, m);
}

Here's a simple example so that you can see what the issues are. It's sorting the integer array {4,3,2,1} .

#include <stdio.h>
#include <stdlib.h>

void merge (int *a, int n, int m) {
    int i, j, k;
    int *x = malloc(n * sizeof (int));
    for (i = 0, j = m, k = 0; k < n; k++) {
        x[k] = j == n      ? a[i++]
             : i == m      ? a[j++]
             : a[j] < a[i] ? a[j++]
             :               a[i++];
    }
    for (i = 0; i < n; i++) {
        a[i] = x[i];
    }
    free(x);
}

void merge_sort (int *a, int n) {
    if (n < 2)
        return;
    int m = n / 2;
    int g;
    printf("a before merge_sort(a,m) %i\n",a);
    printf("m %i\n",m);
    printf("n %i\n",n);
    printf("\n");
    for(g=0;g<m;++g) printf("%i\n", a[g]);
    merge_sort(a, m);
    printf("a after merge_sort(a,m) %i\n",a);
    printf("m %i\n",m);
    printf("n %i\n",n);
    printf("\n");
    for(g=0;g<m;++g) printf("%i\n", a[g]);
    merge_sort(a + m, n - m);
    printf("a after merge_sort(a+m, n-m) %i\n",a);
    printf("m %i\n",m);
    printf("n %i\n",n);
    printf("\n");
    for(g=0;g<m;++g) printf("%i\n",a[g]);
    merge(a, n, m);
    printf("a after merge(a,n,m) %i\n ",a);
    printf("m %i\n",m);
    printf("n %i\n",n);
    for(g=0;g<m;++g) printf("%i\n",a[g]);
}

int main(){
    int test[4] = {4,3,2,1};
    int i;
    merge_sort(&test[0],4);
    printf("\nFinal result:\n");
    for(i=0;i<4;++i){
        printf("%i ",test[i]);
    }
    printf("\n");
}

And here's the output.

Begin of if
End of if(no return)

a before merge_sort(a,m) 0xbfadcebc
m 2
n 4

4
3

Begin of if
End of if(no return)

a before merge_sort(a,m) 0xbfadcebc
m 1
n 2

4

Begin of if

a after merge_sort(a,m) 0xbfadcebc
m 1
n 2

4

Begin of if

a after merge_sort(a+m, n-m) 0xbfadcebc
m 1
n 2

4

a after merge(a,n,m) 0xbfadcebc
 m 1
n 2

3

a after merge_sort(a,m) 0xbfadcebc
m 2
n 4

3
4

Begin of if
End of if(no return)

a before merge_sort(a,m) 0xbfadcec4
m 1
n 2

2

Begin of if

a after merge_sort(a,m) 0xbfadcec4
m 1
n 2

2

Begin of if

a after merge_sort(a+m, n-m) 0xbfadcec4
m 1
n 2

2

a after merge(a,n,m) 0xbfadcec4
 m 1
n 2

1

a after merge_sort(a+m, n-m) 0xbfadcebc
m 2
n 4

3
4

a after merge(a,n,m) 0xbfadcebc
 m 2
n 4

1
2

Final result:
1 2 3 4 

This is what's puzzling me:

Begin of if

a after merge_sort(a+m, n-m) 0xbfadcebc
m 1
n 2

4

a after merge(a,n,m) 0xbfadcebc
 m 1
n 2

3

I'd expect a+m to change the address of a from 0xbfadcebc to something else, but it simply produces the number 4 as an output again. It's as if merge(a+m,nm) didn't have any effect and produced the same as if I had written merge(a,nm).

Furthermore, merge(a,n,m) is not a recursive function, so I'd just expect the function to end after running it. I don't get how this:

a after merge_sort(a,m) 0xbfadcebc
m 2
n 4

3
4

...can be the next step after merge(a,n,m).

Commented code:

/* a = ptr to sub-array */
/* 0 = starting index */
/* m = mid point index */
/* n = ending index */
/* left  half indices = 0 to m-1 */
/* right half indices = m to n   */
void merge (int *a, int n, int m) {
    int i, j, k;
    int *x = malloc(n * sizeof (int)); /* allocate temp array */
    for (i = 0, j = m, k = 0; k < n; k++) {
        x[k] = j == n      ? a[i++]    /* if end of right, copy left */
             : i == m      ? a[j++]    /* if end of left, copy right */
             : a[j] < a[i] ? a[j++]    /* if right < left, copy right */
             :               a[i++];   /* else (left <= right), copy left */
    }
    for (i = 0; i < n; i++) {          /* copy x[] back into a[] */
        a[i] = x[i];
    }
    free(x);                           /* free temp array */
}

/* a = ptr to sub-array */
/* n = size == ending index of sub-array */     
void merge_sort (int *a, int n) {
    if (n < 2)                         /* if < 2 elements nothing to do */
        return;
    int m = n / 2;                     /* m = mid point index */
    merge_sort(a, m);                  /* sort a[0] to a[m-1] */
    merge_sort(a + m, n - m);          /* sort a[m] to a[n-1] */
    merge(a, n, m);                    /* merge the two halves */
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM