快速选择问题

36 篇文章 3 订阅

快速选择问题

快速选择问题。输入 n 个整数和一个正整数k(1kn),输出这些整数从小到大排序后的第 k 个(例如,k=1就是最小值)。 n107

从题目上看,其n的的取值范围为 [1,107] ,由之前的那张算法时间复杂度选择表,可以看出,使用 O(nlog2n) 及以上时间复杂度超时的可能性非常大,这时候最好的选取 O(n) 及以下时间复杂度的算法。

因为是选取一个序列中第 k 大的元素,那么无疑会想到使用分治法进行求解,如果采用像归并排序这样的分治方法,那么时间复杂度毫无疑问是O(nlog2n),这时,不妨想想和归并排序一样采用分治思想的快速排序。由于快速排序不需要合并步骤,且快速选择问题只需要递归一半,其时间复杂度为 O(n)

分治三部曲
划分问题:通过标兵元素,将序列划分为左右两部分,左边的元素都小于等于标兵,右边的元素都大于等于标兵。
递归求解:假设 A[p...r] ,划分后左部分为 A[p...q] 右部分为 A[q+1...r] ,将 k 与划分后A[qp+1]进行比较,小于则只在左部分递归,大于则只在右部分递归。
合并问题:无合并过程。

实现主程序

#include <iostream>
#include <algorithm>
#include <ctime>
#include <fstream>

using namespace std;

// 快速排序算法
int qSort(int *a, int lef, int righ, int k) {
    // 递归边界
    if(lef > righ) {
        return 0;
    }
    // 取标兵值
    int centerV = a[lef + (righ - lef) / 2];

    // 大于标兵值的元素放在标兵值右边
    // 小于标兵值的元素放在标兵值左边
    int i = lef;
    int j = righ;
    while(i <= j) {
        // 从左往右扫描到大于标兵值的元素
        for(; i <= j; i++) {
            if(a[i] >= centerV) {
                break;
            }
        }
        // 从右往左扫描到小于标兵值的元素
        for(; j >= i; j--) {
            if(a[j] <= centerV) {
                break;
            }
        }

        // 退出条件
        if(i > j) {
            break;
        }

        // 交换
        swap(a[i], a[j]);
        i++;
        j--;
    }

    if(k - 1 <= i) {
        // 递归求解左半
        return qSort(a, lef, j, k);
    } else if(k - 1 > i + 1) {
        // 递归求解右半
        return qSort(a, i, righ, k);
    } else{
        return a[k - 1];
    }
}

int quickSort(int *a, int n, int k) {
    return qSort(a, 0, n - 1, k);
}

int main() {
    // 测试数据(小量)
    // int a[] = {4432, 3, -3, 5, 5, 3, 5435, -11, 3423, -1, -4421, 34432};
    // int a[] = {1,2,3,4,9,8,7,8,9,10};
    int a[] = {1,2,3,4,9,33,12,8,9,10};
    int n = 10;
    int k = 9;
    cout << "排序之前:";
    for(int i = 0; i < n; i++) {
        cout << a[i] << " ";
    }
    cout << endl;

    cout << "第" << k << "个数是:" << quickSort(a, n, k) << endl;

    cout << "排序之后:";
    for(int i = 0; i < n; i++) {
        cout << a[i] << " ";
    }
    cout << endl;

    return 0;
}

输出数据

排序之前:1 2 3 4 9 33 12 8 9 109个数是:12
排序之后:1 2 3 4 9 8 9 10 12 33 

Process returned 0 (0x0)   execution time : 0.037 s
Press any key to continue.
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值