快速排序(Quick Sort)及其优化 —— C++

时间复杂度:O(n*logn)
原理:从当前考虑的数组中选择一个元素,以这个元素为基点,之后想办法将其移到一个位置上,使这个数组具有一个性质,即这个元素之前的数据都是小于它的,之后的元素都大于它,接着就是对小于这个元素的数组和大于这个元素的数组分别再进行快速排序
在这里插入图片描述
核心:将选定元素移动满足条件的位置(当前第 i 位元素为 e ,如果 e 大于 v 则 i++,考虑下一位元素,如果 e 小于 v ,则将 e 与第 j+1 位元素交换,之后 j++,i++,考虑下一位元素,遍历完成后将 l 位置元素与第 j 位元素交换,实现排序)
在这里插入图片描述
代码:

// 对arr[l...r]部分进行partition操作
// 返回p,使得arr[l...p-1] < arr[p] ; arr[p+1...r] > arr[p]
template <typename T>
int partition(T arr[], int l, int r){
    //取第一个元素作为基点
    T v = arr[l];
    
    int j = l;//满足初始的情况下 arr[l+1...j] 为空集
    
    // arr[l+1...j] < v ; arr[j+1...i) > v
    for( int i = l + 1 ; i <= r ; i ++ ){
        //arr[i] > v 什么都不用做,i++
        if( arr[i] < v ){
            j ++;
            swap( arr[j] , arr[i] );//交换 arr[j+1] 和 arr[i]
        }
    }
    
    swap( arr[l] , arr[j]); //最后交换arr[l] 和 arr[j]
    return j;
}

// 对arr[l...r]部分进行快速排序
template <typename T>
void quickSort(T arr[], int l, int r){
    if( l >= r )//可优化
        return;

    int p = partition(arr, l, r);
    quickSort(arr, l, p-1 );
    quickSort(arr, p+1, r);
}

优化1:随机快速排序法:在近乎有序的数组中,选第一个元素为基点,快速排序在最差情况下退化为O(n^2)级别排序,所以随机选择一个元素作为基点,其退化的可能性极低
在这里插入图片描述
代码:

srand(time(NULL));//生成随机种子

template <typename T>
int _partition(T arr[], int l, int r){
    //生成 [l , r] 范围内的随机数,并放到第一个位置
    swap( arr[l] , arr[rand()%(r-l+1)+l] );
    T v = arr[l];
    int j = l;
    for( int i = l + 1 ; i <= r ; i ++ )
        if( arr[i] < v ){
            j ++;
            swap( arr[j] , arr[i] );
        }
        
    swap( arr[l] , arr[j]);
    return j;
}

优化2:双路快速排序:有大量重复数据的数组,很可能把数组分成极度不平衡的两部分,其退化为O(n^2)级别的算法,所以将大于小于 v 的元素分别放在两端位置,等于 v 的元素被近乎均匀的平分到两部分
在这里插入图片描述
操作图示
从 i 的位置开始向后扫描,当我们面对的元素仍然小于 v 的时候,继续向后扫描,直到大于等于 v ,停止扫描,而从 j 则以类似方法向前扫描,直到元素小于等于 v
在这里插入图片描述
交换 i ,j 位置的两元素,i++,j–,继续扫描,直到 i >j
在这里插入图片描述
代码

template <typename T>
int partition2(T arr[], int l, int r){
    swap( arr[l] , arr[rand()%(r-l+1)+l] );
    T v = arr[l];

    // arr[l+1...i) <= v; arr(j...r] >= v
    int i = l+1, j = r;
    while( true ){
        while( i <= r && arr[i] < v )
            i ++;

        while( j >= l+1 && arr[j] > v )
            j --;

        if( i > j )
            break;
            
        swap( arr[i] , arr[j] );//此时arr[i] >= v  , arr[j] <= v,交换两元素 
        i ++;
        j --;
    }
    swap( arr[l] , arr[j]);// j-- 后 arr[j] 位于小于 v 部分的末尾
    return j;
}

template <typename T>
void quickSort(T arr[], int l, int r){
    if( r - l <= 15 ){
        insertionSort(arr,l,r);
        return;
    }

    int p = partition2(arr, l, r);
    quickSort(arr, l, p-1 );
    quickSort(arr, p+1, r);
}

优化3:三路快速排序法:将数组分为三部分,小于 v ,等于 v ,大于 v,这样分割后,对于等于 v 的部分就不用考虑
在这里插入图片描述
当前处理元素为第 i 位元素 e ,
如果 e =v ,i++,处理下一位元素,
如果 e < v ,将第 lt+1 位元素与 e 交换,lt++,i++,处理下一位元素
如果 e > v ,将第 gt-1 位元素与 e 交换,gt-- ,接着处理第 i 位元素
i =gt 时,排序结束,接着对小于 v 以及大于 v 的数组进行快速排序
代码

srand(time(NULL));

template <typename T>
void quickSort3Ways(T arr[], int l, int r){
    if( r - l <= 15 ){
        insertionSort(arr,l,r);
        return;
    }

    swap( arr[l], arr[rand()%(r-l+1)+l ] );

    T v = arr[l];

    //保证逻辑有一个正确的开始
    int lt = l;         // arr[l+1...lt] < v
    int gt = r + 1;     // arr[gt...r] > v
    int i = l+1;        // arr[lt+1...i) == v
    while( i < gt ){
        if( arr[i] < v ){
            swap( arr[i], arr[lt+1]);
            i ++;
            lt ++;
        }
        else if( arr[i] > v ){
            swap( arr[i], arr[gt-1]);
            gt --;
        }
        else{ // arr[i] == v
            i ++;
        }
    }

    swap( arr[l] , arr[lt] );
    quickSort3Ways(arr, l, lt-1);
    quickSort3Ways(arr, gt, r);
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值