查找数组中第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章-中位数和顺序统计量

时间: 2024-08-08 19:57:16

查找数组中第i小的元素的相关文章

《数据结构、算法与应用》8.(顺序查找数组中第一个出现指定元素的位置)

最近在读<数据结构.算法与应用>这本书,把书上的习题总结一下,用自己的方法来实现了这些题,可能在效率,编码等方面存在着很多的问题,也可能是错误的实现,如果大家在看这本书的时候有更优更好的方法来实现,还请大家多多留言交流多多指正,谢谢 8. 从左至右检查数组a[0:n-1]中的元素,以查找雨x相等的那些元素.如果找到一个元素与x相等,则函数返回x第一次出现所在的位置.如果在数组中没有找到这样的元素,函数则返回-1. // // main.cpp // Test_08 // // Created

查找数列中第K小的元素(C语言版)

今天在看<算法:C语言实现>时,在快速排序那一章最后一节讲述了利用快速排序的思想,快速排序每次划分后在枢轴的左边的元素都比枢轴小,在枢轴右边的数都比枢轴大(或相等),而划分后枢轴本身就放在了(有序时)它自身应该在的位置,在每次划分后判断枢轴下标和k的大小就可以快速找出数列中第k小的数了. 看完之后,我想既然利用快速排序的思想可以很快的找到第k小的数,那么能不能利用计数排序的思想来查找第k小的数呢,仔细一想,完全可以!计数排序是利用一个计数数组C来记录待排序数组中各个不同数值出现的次数,然后通过

查找数组中出现次数最多的元素(一次遍历)

采用阵地攻守的思想:第一个数字作为第一个士兵,守阵地:count = 1:遇到相同元素,count++;遇到不相同元素,即为敌人,同归于尽,count--:当遇到count为0的情况,又以新的i值作为守阵地的士兵,继续下去,到最后还留在阵地上的士兵,有可能是主元素.再加一次循环,记录这个士兵的个数看是否大于数组一般即可. 代码如下 public int Solution(int [] array) { int len = array.length; int count=1;//初始化第一个士兵为

挑战面试编程:查找数组中第k大的数

查找数组中第k大的数 问题: 查找出一给定数组中第k大的数.例如[3,2,7,1,8,9,6,5,4],第1大的数是9,第2大的数是8-- 思路: 1. 直接从大到小排序,排好序后,第k大的数就是arr[k-1]. 2. 只需找到第k大的数,不必把所有的数排好序.我们借助快速排序中partition过程,一般情况下,在把所有数都排好序前,就可以找到第k大的数.我们依据的逻辑是,经过一次partition后,数组被pivot分成左右两部分:S左.S右.当S左的元素个数|S左|等于k-1时,pivo

JS数组常用函数以及查找数组中是否有重复元素的三种常用方法

阅读目录: DS01:常用的查找数组中是否有重复元素的三种方法 DS02:常用的JS函数集锦 DS01.常用的查找数组中是否有重复元素的三种方法 1. 1 var ary = new Array("111","22","33","111"); 2 var s = ary.join(",")+","; 3 for(var i=0;i<ary.length;i++) { 4 if(s.

解析、查找数组中重复出现的元素(Java)

 解析.查找数组中重复出现的元素,Java实现. <数据结构与算法分析:解析.查找数组中重复出现的元素> 问题描述:一个结构化数据,假设事先按照某种顺序排好序(比如升序)的一个数组中,无规则.重复出现若干次某个相同元素,形如有序数组data: data = {  "A", "A", "B", "C", "C", "D", "D" , "D&q

[LeetCode] Kth Smallest Element in a Sorted Matrix 有序矩阵中第K小的元素

Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth smallest element in the matrix. Note that it is the kth smallest element in the sorted order, not the kth distinct element. Example: matrix = [ [ 1, 5

数组中第K大的元素

数组中第K大的元素总结 解法1: 我们可以对这个乱序数组按照从大到小先行排序,然后取出前k大,总的时间复杂度为O(n*logn + k). 解法2: 如果k很小,比如第五个最大的数,而整个数组的长度非常的大,那么,还有一种方法就是,我做k遍找最大的数,每做一遍,就把最大的放在数组的最后面(遍历一次找出最大的数例如冒泡,选择排序都可以.),然后减少数组扫描的范围,就可以把第k大的数找出来,这样做的复杂度就是O(K*N),在K很小的情况下,还是不错的. 解法3: 利用快速排序的思想,从数组S中随机找

九度OJ 1534 数组中第K小的数字

题目1534:数组中第K小的数字 时间限制:2 秒 内存限制:128 兆 特殊判题:否 提交:1524 解决:307 题目描述: 给定两个整型数组A和B.我们将A和B中的元素两两相加可以得到数组C. 譬如A为[1,2],B为[3,4].那么由A和B中的元素两两相加得到的数组C为[4,5,5,6]. 现在给你数组A和B,求由A和B两两相加得到的数组C中,第K小的数字. 输入: 输入可能包含多个测试案例. 对于每个测试案例,输入的第一行为三个整数m,n, k(1<=m,n<=100000, 1&l