對比快速排序,理解歸併排序

對比快速排序來理解歸併排序。

有時經常講歸併排序和快速排序記混亂,因爲兩者都用到了分治法。其實兩者的不同之處非常明顯。

快速排序:“先治後分”,

void quickly_sort(int arr[], int low, int high) {
  if (low < high) {
    // 先治後分
    int pivot = _qucikly_sort(arr, low, high);  //治
    quickly_sort(arr, low, pivot-1); //分
    quickly_sort(arr, pivot + 1, high); //分
  }
}

歸併排序:“先分後治”。

void merge_sort_up2down(int a[], int start, int end) {
    if(a==NULL || start >= end)
        return ;
    // 先分後治
    int mid = (end + start)/2;
    merge_sort_up2down(a, start, mid); // 分
    merge_sort_up2down(a, mid+1, end); // 分
    merge(a, start, mid, end); // 治
}

“分”的過程用遞歸實現起來分簡單,主要是理解兩者的“治”。

快速排序的根本處理是:如何在選定一個元素後,將這個元素放在合適的位置,使得元素左邊都是小於這個元素的,右邊都是大於這個元素的(挖坑填坑法)

int _qucikly_sort(int arr[], int low, int high) {
  int pivot = arr[low]; //挖第一個坑,把“蘿蔔”放進籃子
  while(low<high) { //開始循環挖坑填坑
    //如果low等於high,說明找坑的過程中,找到了上一次挖的坑,因此可以停止了
    while(low<high && arr[high]>=pivot) //從右邊往左邊找填坑的元素(比pivot小的元素)。 2,4,6的過程
      --high;
    arr[low] = arr[high]; //將找到之後,挖出來,填到左邊的坑裏
    while(low<high && arr[low]<=pivot) //從左邊往右邊找填坑的(比pivot大的元素)。3,5的過程
      ++low;
arr[high] = arr[low];//找到之後,填到右邊的坑裏
  }
  arr[low] = pivot; //籃子裏的“蘿蔔”填到坑裏
  return low;//返回這個坑的位置,作爲分而治之的中軸
}

歸併排序的根本處理是:如何將兩個有序的數組,合併成一個有序數組(申請一個數組,大小是兩個有序數組(原數組的兩個子數組)的大小之和,遍歷比較兩個數組的元素,按大小放進新數組,將新數組替換原數組的子數組即可):

void merge(int a[], int start, int mid, int end) {
    int *tmp = (int *)malloc((end-start+1)*sizeof(int));    // tmp是彙總2個有序區的臨時區域
    int i = start;            // 第1個有序區的索引
    int j = mid + 1;        // 第2個有序區的索引
    int k = 0;                // 臨時區域的索引

    while(i <= mid && j <= end) {
        if (a[i] <= a[j])
            tmp[k++] = a[i++];
        else
            tmp[k++] = a[j++];
    }

    while(i <= mid)
        tmp[k++] = a[i++];

    while(j <= end)
        tmp[k++] = a[j++];

    // 將排序後的元素,全部都整合到數組a中。
    for (i = 0; i < k; i++)
        a[start + i] = tmp[i];

    free(tmp);
}


這樣,都過簡單的代碼對比,就可以很簡單的分清楚兩者的關係與不同。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章