2015-03-24 54 views
0

所以我在看Rosetta Code的合併排序的C示例,我對merge()函數的工作原理有點困惑。我認爲這是他們使用的語法將我帶到冒號和?的。merge_sort()中的merge()如何工作?

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); 
} 

merge()函數的for循環究竟發生了什麼?有人可以解釋嗎?

+1

這就是所謂的條件(或有時三元)運算符。你可以閱讀關於它[這裏](http://www.cplusplus.com/articles/1AUq5Di1/)。 – clcto 2015-03-24 22:56:50

+1

總而言之,這一個運作不佳。如果低端首先完成,則不需要將序列的高端複製到臨時存儲器。原來陣列中已經存在的東西已經就位。 – WhozCraig 2015-03-24 23:02:13

+0

哇,我真的不明白爲什麼代碼是這樣寫的。這對於簡單的合併例程來說似乎太複雜了。 – templatetypedef 2015-03-24 23:08:23

回答

0

閱讀評論:

void merge (int *a, int n, int m) { 
    int i, j, k; 
    // inefficient: allocating a temporary array with malloc 
    // once per merge phase! 
    int *x = malloc(n * sizeof (int)); 
    // merging left and right halfs of a into temporary array x 
    for (i = 0, j = m, k = 0; k < n; k++) { 
     x[k] = j == n  ? a[i++] // right half exhausted, take from left 
      : i == m  ? a[j++] // left half exhausted, take from right 
      : a[j] < a[i] ? a[j++] // right element smaller, take that 
      :    a[i++]; // otherwise take left element 
    } 
    // copy temporary array back to original array. 
    for (i = 0; i < n; i++) { 
     a[i] = x[i]; 
    } 
    free(x); // free temporary array 
} 

void merge_sort (int *a, int n) { 
    if (n < 2) 
     return; 
    int m = n/2; 
    // inefficient: should not recurse if n == 2 
    // recurse to sort left half 
    merge_sort(a, m); 
    // recurse to sort right half 
    merge_sort(a + m, n - m); 
    // merge left half and right half in place (via temp array) 
    merge(a, n, m); 
} 

一種更簡單,更高效的版本merge功能,只用一半的臨時空間:

static void merge(int *a, int n, int m) { 
    int i, j, k; 
    int *x = malloc(m * sizeof (int)); 
    // copy left half to temporary array 
    for (i = 0; i < m; i++) { 
     x[i] = a[i]; 
    } 
    // merge left and right half 
    for (i = 0, j = m, k = 0; i < m && j < n; k++) { 
     a[k] = a[j] < x[i] ? a[j++] : x[i++]; 
    } 
    // finish copying left half 
    while (i < m) { 
     a[k++] = x[i++]; 
    } 
} 

merge_sort的更快版本包括分配一個臨時的數組x的大小爲n * sizeof(*a),並將其傳遞給遞歸函數merge_sort1,該函數調用merge,並將其作爲額外的參數,作爲w埃爾。在merge的邏輯也與此一半多的比較改善上ij

static void merge(int *a, int n, int m, int *x) { 
    int i, j, k; 

    for (i = 0; i < m; i++) { 
     x[i] = a[i]; 
    } 
    for (i = 0, j = m, k = 0;;) { 
     if (a[j] < x[i]) { 
      a[k++] = a[j++]; 
      if (j >= n) break; 
     } else { 
      a[k++] = x[i++]; 
      if (i >= m) return; 
     } 
    } 
    while (i < m) { 
     a[k++] = x[i++]; 
    } 
} 

static void merge_sort1(int *a, int n, int *x) { 
    if (n >= 2) { 
     int m = n/2; 
     if (n > 2) { 
      merge_sort1(a, m, x); 
      merge_sort1(a + m, n - m, x); 
     } 
     merge(a, n, m, x); 
    } 
} 

void merge_sort(int *a, int n) { 
    if (n < 2) 
     return; 
    int *x = malloc(n/2 * sizeof (int)); 
    merge_sort1(a, n, x); 
    free(x); 
} 
+0

因此,如果我錯了,請諒解,但Mergesort看起來很像很多Quicksort ......它們究竟有什麼不同? – James4701 2015-03-25 22:25:16

+0

'mergesort'和'qsort'類似是有限的:它們都在數據的一個分區上使用遞歸。 'mergesort'系統地將數據集分成兩半大小相等的數據集,並將它們合併到線性時間中,產生* O(n.log(n))*的複雜度,最壞情況和平均情況,是一種穩定的排序,但需要* O(n)*工作空間。 'qsort'使用啓發式方法來分割數據集並對各個部分進行排序。它需要很少的額外空間,平均情況下複雜度爲* O(n.log(n))*,但它不穩定,最壞情況下的複雜度爲* O(n^2)*,這可能會產生問題。 – chqrlie 2015-03-25 22:38:36