xiaojie4620

导航

两种排序

一、快速排序

//快速排序
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 定义函数类型,因为返回的逆序对数量是一个整数,而且有可能很大

posted on 2022-03-14 18:12  kuokuo  阅读(29)  评论(0编辑  收藏  举报