快速排序 | 快速选择排序

快速排序思想:任意选择数组中的一个元素,作为中心轴(一般选取末尾元素),其余元素与中心轴对比大小,小于中心轴的依次放左边,大于中心轴的依次放右边。最终得到一个中心轴左边全是小于中心轴元素的元素,右边全是大于中心轴元素的元素,但两边的元素是无序的。  要达到整个素组排序的目的,需要对两边元素递归调用这个方法。  快速排序的时间复杂度为O(nlogn)。

快速排序代码实现:

void quickSort(int nums[ ], int l, int r) {
        if(l >= r){   //当素组元素只有1个时返回
            return;
        }
        int x = nums[r], i = l - 1; //选定末尾元素为中心轴X;

        //小于中心轴元素的元素从0号元素开始依次互换,剩余的元素都是大于中心轴的元素
        for (int j = l; j < r; ++j){  
            if (nums[j] <= x) {
                swap(nums[++i], nums[j]);
            }
        }

        //最后选择的将中心轴元素X(nums[r])与最后一位小于中心轴元素的下一个位置交换元素。
        swap(nums[i + 1], nums[r]);
        

        //中心轴左右素组区间重复这个方法,最终达到整个素组有序。
        quickSort(nums,i+2,r);
        quickSort(nums,l,i);
        
    }


int main(int argc, char** argv) {
    int nums[] = {4,6,7,8,4,2,6,3,4,20,6,7,3,19,33,11,23,7,5,5,3,3,56,7};
    int n = sizeof(nums) / sizeof(nums[0]);
    quickSort(nums,0,n-1);
    
    for(int i=0;i<n;i++){
        cout<<nums[i]<<" ";
    }
    return 0;    
}

快速选择排序思想:利用快速排序思想,找到指定元素。如找到素组中第K大的元素(假设他的下标为q)。可以利用每一次递归调用中心轴的改变,中心轴下标可能会大于小于或等于下标为q的元素, 我们只需要中心轴下标等于q时,就可以返回该元素不需要再进行递归排序(中心轴的右边都是大于中心轴,左边都是小于中心轴的性质)。当中心轴下标大于q时,只需要对中心轴左区间进行递归调用,小于时进行右区间递归调用,以达到下一次中心轴下标可能会等于q目的。同时防止例如[7,6,5,4,3,2,1]这样的素组,会使每次使中心轴为末尾元素时形成每次递归只能移动一位元素到前面,使得时间复杂度为O(n的平方),所以我们不以末尾元素为中心轴元素,而是随机选择一位元素为中心轴元素。

快速选择排序代码实现:

//快速排序函数  

inline int quickSort(int nums[], int left, int  right){

        int x = nums[right];  //实现选择末尾元素为中心轴,即选择之前随机元素为中心轴

        //当for循环次数足够多时,++j比j++的效率要高一些,因为j++要申请临时空间存储 j 的值。

        int i = left-1;

        for(int j = left; j < right; ++j){

                if(nums[j] <= x){

                        swap(nums[++i],nums[j]);

                }

        }

        swap(nums[i+1],nums[right]);

        return i + 1;

//随机选择一位元素作为中心轴元素函数,inline表示为内联函数,可以理解为用到这个函数的地方并不是调用这个函数,而是把这个函数内嵌到用到这个函数的地方,这样可以节约函数调用的开销。

inline int random(int nums[], int left,int  right){ 

        int i = rand() % (right - left +1) + left;  //生成在 [left,right] 闭区间的随机数

        swap(nums[i], nums[right]); //使随机元素交换到末尾元素,后选择末尾元素为中心轴。

        return quickSort(nums, left, right);

}

int quickSelectSort(int nums[], int left, int right, int aim ){

       if(left >= right){

                return nums[right];

        }

        int q = random(nums, left, right);  //q为中心轴的下标

        if(q == aim){

                return nums[aim];

        }else{

                return q > aim ? quickSelectSort(nums, 0, q-1, aim) : quickSelectSort(nums, q+1, right,                 aim);

        }

}

int main(int argc, char** argv) {
    int nums[] = {4,6,7,8,4,2,6,3,4,20,6,7,3,19,33,11,23,7,5,5,3,3,56,7};
    int n = sizeof(nums) / sizeof(nums[0]);
    int result = quickSelectSort(nums, 0, n-1, n-k);//k为第几大的元素
    
    for(int i=0;i<n;i++){
        cout<<nums[i]<<" ";
    }

    cout<<endl<<result;
    return 0;    
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值