兩種排序
阿新 • • 發佈:2022-03-14
一、快速排序
//快速排序 void quick_sort(int a[],int l,int r) { if( l >= r ) return; int i = l - 1, j = r + 1, x = a[l + r >> 1];// x表示中間值 l + r >> 1 == (l + r) /2; while( i < j ) { do i++ ;while( a[i] < x ); do j++ ;while( a[j] > x ); if( i < j )swap(a[i],a[j]); } quick_sort(a,l,j), quick_sort(a,j + 1,r);//對分開的倆塊分別進行排序即可 }
- 類似於雙指標演算法
-
1.如果
a[i] < x
則迴圈繼續 若不成立 do i++ 停止執行 直到 2 停止時if( i < j )swap(a[i],a[j]); 繼續執行程式碼
- 2.如果
a[j] > x
則迴圈繼續 若不成立 do j++ 停止執行 直到 1 停止時if( i < j )swap(a[i],a[j]); 繼續執行程式碼
二、歸併排序
//歸併排序 void merge_sort(int a[],int l, int r) { if( l >= r ) return; int mid = l + r >> 1;//分治 merge_sort(a,l,mid) , merge_sort(a,mid+1,r);//遞迴處理子問題 int i = l, j = mid + 1,k = 0; while( i <= mid && j <= r ) { if( a[i] >= a[j] ) t[k++] = a[j++]; else t[k++] = a[i++]; } while( i <= mid ) t[k++] = a[i++];//兩個 while 中 必有一個是不成立的 while( j <= r ) t[k++] = a[j++]; for( int i = l,j = 0; i <= r; i++ ) a[i] = t[j++]; //將臨時陣列的值賦值回到原陣列 }
- 為什麼不用 mid - 1 作為分隔線呢
即 merge_sort(q, l, mid - 1 ), merge_sort(q, mid, r)
因為 mid = l + r >> 1 是向下取整,mid 有可能取到 l (陣列只有兩個數時),造成無限劃分
解決辦法: mid 向上取整就可以了, 即 mid = l + r + 1 >> 1
三、逆序對數量(歸併排序解決)
//逆序對的個數(歸併排序 long long merge_sort_2(int a[],int l, int r) { //int ans = 0; if( l >= r ) return 0; int mid = l + r >> 1; long long ans = merge_sort_2(a,l,mid) + merge_sort_2(a,mid+1,r); int i = l, j = mid + 1,k = 0; while( i <= mid && j <= r ) if( a[i] > a[j] ) { t[k++] = a[j++]; ans += mid - i + 1; } else t[k++] = a[i++]; while( i <= mid ) t[k++] = a[i++]; while( j <= r ) t[k++] = a[j++]; for( int i = l,j = 0; i <= r; i++ ) a[i] = t[j++]; return ans; }
- 此處要使用long long 定義函式型別,因為返回的逆序對數量是一個整數,而且有可能很大