寻找数列中第k大的数算法分析

问题描述:给定一系列数{a1,a2,...,an},这些数无序的,现在求第k大的数。

看到这个问题,首先想到的是先排序,然后直接输出第k大的数,于是得到啦基于排序的算法

算法一:

#include<iostream>
#include<algorithm>
using namespace std;
bool cmp(int a, int b){ return a > b; }
int main(){
int k;
int a[9] = { 6, 5, 9, 8, 2, 1, 7, 3, 4 };
cout << "Input k:";
cin >> k;
sort(a, a + 9, cmp);
cout << a[k - 1] << endl;
return 0;
}

算法耗时主要在排序上,于是这个算法复杂度是O(nlogn);

算法二:

算法二是基于分解的方法,问题求解的是第k大的数,若果我将这系列数全部排序肯定会做太多无用功,比如我只需找出第k大,我可以先找出1大,第2大....第k大,在结束,此时时间为O(kn),当k比较少时候算法复杂度为0(n),若当k是关于n的函数时候算法复杂度为O(n2),最好的情况是k=1和k=n,最坏的情况是k=n/2,O(n)=<f(n)<=O(n2/2);具体代码如下:

#include<iostream>
using namespace std;
#include<cmath>
#define m int(pow(-2,31)); /*将m赋值为最小的整数*/
int Find_Kth(int a[], int n, int k);
int main(){
int k;
int a[9] = { 6, 5, 9, 8, 2, 1, 7, 3, 4 };
cout << "Input k:";
while (cin >> k){
cout << Find_Kth(a, 9, k) << endl;
}
return 0;
}
int Find_Kth(int a[], int n, int k){
int i,j, redex=0, NewMax = a[0];
for (i = 0; i < k; i++){ /*每次采用打擂台方法找到本次最大值后赋值为m*/
for (i = 0; i < n; i++)
if (a[i]>NewMax){
NewMax = a[i];
redex = i;
}
a[redex] = m;
}
return NewMax;
}

算法二有局限性,复杂度取决于k值,下面还是采用基于分解的思想,我们需要的是求第k大的数,于是可以采用快速排序的思想,任意选择一个数key将这序列数分解为s1和s2两个序列,其中s1中的数全部小于key,而s2中的数全部大于或等于key(key是s2中的最小的数),设s1和s2中元素个数为|s1|和|s2|,如果k==|s2|,那摩说明第k大的数恰好为key,如果k<|s2|,那么问题转化为求|s2|中第k大的数,如果k>|s2|,那么问题转化为求s1中第k-|s2|大的数,这样所有的过程可以通过递归来实现,于是有啦算法三。

算法三:
#include<iostream>
using namespace std;
int Find_Kth(int *a,int left,int right,int k);
int main(){
int k;
int a[9] = {6,5,9,8,2,1,7,3,4};
cout << "Input k:";
cin >> k;
cout << Find_Kth(a, 0, 8, k) << endl; /*输出第k大的数*/
return 0;
}
int Find_Kth(int *a,int left,int right, int k){
int key = a[left]; /*设定关键值*/
int low = left,high=right;
while (high>low){ /*类似于快速排序*/
while (a[high] >= key&&high>low)
high--;
a[low] = a[high];
while (a[low] <= key&&high>low)
a[low++];
a[high] = a[low];
}/*循环跳出必定有high=low*/
a[low] = key;
int r = right - low + 1; /*右端元素个数*/
if (k== r)
return a[low]; //恰好a[low]为第k大值
else if (k < r)
return Find_Kth(a, low+1, right, k); //第k大的值在a[low]右边第k大值
else
return Find_Kth(a, left, low - 1, k - r); /*第k大值在a[low]右边序列的第r-k大的值*/
}

事实上,C++的STl早已经为我们提供啦函数nth_element,包含头文件#include<iostream>中.nth_element有四个参数,第一个和第三个为begin和end的地址,表示搜索范围是区间[begin,end)里面的数,第二个参数为找的第k个数的地址,第四个参数为cmp函数,函数可以看成 void element(int*begin,int*Nth,int*end,boo(*pdrf)(int a,int b));

#include<iostream>
#include<algorithm>
using namespace std;
bool cmp(int a, int b){
return a > b;
}
int main(){
int k;
int a[9] = { 6, 5, 9, 8, 2, 1, 7, 3, 4 };
cout << "Input k:";
while (cin >> k){
nth_element(a, a + k-1,a+9, cmp); //将第k大的数放在k-1位置
cout << a[k - 1] << endl;
}
return 0;
}

时间: 2024-09-29 20:46:27

寻找数列中第k大的数算法分析的相关文章

寻找数列中第K大的数

版权所有 未经允许 请勿擅自商用 转载请指明出处 最早看到这个问题是在那本Mark写的数据结构与算法分析的书中引论部分,当时就是瞅瞅,到了最近,在实际应用中,我需要查找一些列的数中第k大的数时,我才重新回顾品味这个问题.现在,实际问题中,我还暂时没有解决问题,但是这段思考过程很有意思,在这里给大家品味下. 具体的问题有点复杂,在这里就不赘述了,暂且将这个问题形式化的描述如下: 给定一个有限无序数列记做{an},从这个数列中找出第k大的数. 输入:数列{an},k 输出:第k大的数 首先,有个最简

[经典算法题]寻找数组中第K大的数的方法总结

[经典算法题]寻找数组中第K大的数的方法总结 责任编辑:admin 日期:2012-11-26 字体:[大 中 小] 打印复制链接我要评论 今天看算法分析是,看到一个这样的问题,就是在一堆数据中查找到第k个大的值. 名称是:设计一组N个数,确定其中第k个最大值,这是一个选择问题,当然,解决这个问题的方法很多,本人在网上搜索了一番,查找到以下的方式,决定很好,推荐给大家. 所谓"第(前)k大数问题"指的是在长度为n(n>=k)的乱序数组中S找出从大到小顺序的第(前)k个数的问题.

顺序统计:寻找序列中第k小的数

最直观的解法,排序之后取下标为k的值即可. 但是此处采取的方法为类似快速排序分块的方法,利用一个支点将序列分为两个子序列(支点左边的值小于支点的值,支点右边大于等于支点的值). 如果支点下标等于k,则支点就是查找的值,如果支点的下标大于k,则在左子序列里继续寻找,如果支点下标小于k,则继续在支点右子序列里面继续寻找第(k-支点下标)小的值. c#实现算法如下: public class FindSpecialOrderElement<T> where T : IComparable<T&

挑战面试编程:查找数组中第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

【LeetCode-面试算法经典-Java实现】【215-Kth Largest Element in an Array(数组中第K大的数)】

[215-Kth Largest Element in an Array(数组中第K大的数)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 代码下载[https://github.com/Wang-Jun-Chao] 原题 Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth d

找出整数中第k大的数

一  问题描述: 找出m个整数中第k(0<k<m+1)大的整数. 二  举例: 假设有12个整数:data[1, 4, -1, -4, 9, 8, 0, 3, -8, 11, 2, -9],请找出第5大的数(容易知道是0). 三   算法思路:        一种基于快排思想的算法可以在O(n)复杂度内找到第k大的数,首先要知道partition这个函数,它可以调整一个序列 使小于key的元素都排在key左边,大于key的元素都排在key右边,key可以在这个序列中任意选择,一般选择给定序 列

找一个数组中第K大的数

快排思想,选取序列的一个key进行划分,小于key的分在左边,大于key的在右边,key的位置-low+1就是最后一个元素是key的序列中元素的数量,当元素数量大于K时,就在左半部分递归找,等于时 arr[key]就是第K 大的元素,小于K时,在右边递归找第k-num大的元素 /** * 文件名:FindK.java * 时间:2014年11月7日上午11:23:43 * 作者:修维康 */ package chapter7; /** * 类名:FindK 说明:找到一个数组中第K大的元素 */

查找两个有序序数组(一个递增、一个递减)中第K大的数

题目不难,关键是边界条件要想清楚.先写一个时间复杂度为O(K) 的解法. #include <iostream> using namespace std; //a[] increase //b[] decrease //use ret_value to return the result //function ret reprsent the error if not 0 int find_k(int a[], int b[], int m, int n, int k, int& re

查找无序数组中第K大的数

思路: 利用快速排序的划分思想 可以找出前k大数,然后不断划分 直到找到第K大元素 代码: #include <iostream> #include <algorithm> #include <cstdio>5 using namespace std; int findK(int left, int right, int arr[], int k) { if(left >= right) return arr[left]; int first = left, la