1. 程式人生 > 其它 >兩種排序

兩種排序

一、快速排序

//快速排序
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 定義函式型別,因為返回的逆序對數量是一個整數,而且有可能很大