查找数组中第i小的元素

        查找并输出数组中第i小的元素,这样的题目我们可以先对数组进行排序,然后输出相对应的第i小的元素;还有另外一种方法,一种解决选择问题的分治算法,该算法是以快速排序算法为模型的,与快速排序一样,我们仍然将输入数组进行划分,但与快速排序不同的是,快速排序会递归处理划分的两边,而该选择方法select只处理划分的一边。这一差异会在性能分析中体现出来:快速排序的期望运行时间为O(nlog(n)),而select的选择期望运行时间是O(n)。


1、对数组进行排序,然后输入第i小的元素,这里排序算法用的是插入排序。

#include <iostream>

using namespace std;

int select(int a[], int n, int i);

int main(void)
{
    int a[5] = {4, 67, 8, 2, 3};

    cout<<select(a, 5, 4)<<endl;

    return 0;
}

static void InsertSort(int a[], int n)
{
    int i, j;

    for(i = 1; i < n; i++)
    {
        int x = a[i];
        for(j = i; j > 0 && a[j-1] > x; j--)
            a[j] = a[j-1];
        a[j] = x;
    }
}

int select(int a[], int n, int i)
{
    InsertSort(a, n);

    return a[i-1];
}

2、递归进行选择数组中第i小的元素,select函数运行过程如下:刚开始检查递归的基本情况,当a[]包含只有一个元素时,i必须等于1,直接返回。其他情况下,就会调用Partition函数,将数组划分为两个子数组(可能为空的),a[left..j-1]和a[j+1..right],使得a[left..j-1]中每个元素都小于等于a[j],而a[j]小于a[j+1..right]中的每个元素。与快速排序一样,我们称a[j]为主元,接着计算子数组内a[left..j]中的元素个数k,即处于划分的低区的元素个数加1。然后检查a[j]是否是第i小的元素,如果是接下来直接返回,否则的话确定第i小的元素落在a[left..j-1]和a[j+1..right]两个子数组中的哪一个。如果i<k,则要查找的元素落在了划分的低区,则接下来在低区的子数组中继续递归查找;如果i>k,则要查找的元素落在了高区。我们已经知道了有k个值小于aleft..right]中的第i小的元素,即a[left..j]内的元素,所以我们要找的元素必然是a[j+1..right]中的第I-k小的元素,再进行递归查找。

#include <iostream>

using namespace std;

int select(int a[], int left, int right, int i);

int main(void)
{
    int a[5] = {4, 67, 8, 2, 3};

    cout<<select(a, 0, 4, 3)<<endl;

    return 0;
}

static void Swap(int &a, int &b)
{
    int t = a;
    a = b;
    b = t;
}
static int Partition(int a[], int left, int right)
{
    int t, i, j;

    t = a[right];
    i = left;
    for(j = left; j < right; j++)
    {
        if(a[j] < t)
            Swap(a[i++], a[j]);
    }
    Swap(a[i], a[right]);

    return i;
}

int select(int a[], int left, int right, int i)
{
    if(left == right)
        return a[left];
    int j = Partition(a, left, right);
    int k = j - left + 1;

    if(k == i)
        return a[j];
    else if(i < k)
        return select(a, left, j-1, i);
    else
        return select(a, j+1, right, i-k);
}


参考资料:

1、《算法导论》(第三版)第9章-中位数和顺序统计量



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值