寻找最小的k个数
来源:互联网 发布:境外网络电视直播.apk 编辑:程序博客网 时间:2024/06/09 20:14
题目:输入n个整数,输出其中最小的k个
思路一、快速排序+遍历
先对n个整数快速排序,平均所费的时间为nlogn,之后再遍历序列中前k个元素的输出
(总的时间复杂度为O(nlogn+k) = O(nlogn))
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
思路二、选择排序+遍历
1、遍历n个数,把最先遍历到的k个数存入到大小为k的数组中,假设它们即使最小的k个数;
2、对这k个数利用交换排序找出这k个元素中的最大值kmax,时间复杂度为O(k);
3、继续遍历n-k个数,假设每一次遍历到的新的元素的值为x,把x与kmax比较:如果 x < kmax ,用x替换kmax,并回到第二步重新找出k个元素的数组中最大元素kmax‘;如果 x >= kmax ,则继续遍历不更新数组。每次遍历更新或不更新数组所用的时间为O(k),故整趟下来,时间复杂度为nO(k)=O(nk)
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
思路三、维护容量为k的最大堆
1、用容量为k的最大堆存储最先遍历到的k个数,同样假设它们即是最小的k个数;
2、堆中元素是有序的,令k1<k2<...<kmax(kmax设为最大堆中的最大元素)
3、遍历剩余n-k个数。假设每一次遍历到的新的元素的值为x,把x与堆顶元素kmax比较:如果 x < kmax ,用x替换kmax,然后更新堆(用时logk);否则不更新堆。总的时间复杂度为O(nlogk)
与思路二的区别在于堆中进行查找和更新的时间复杂度均为O(logk),但是在数组中找出最大元素,时间复杂度为O(k).
注意一个误区:并不是取出堆顶元素之后,把原来堆顶元素的儿子送到堆顶,而是如图所示,16被删除之后,堆中的最后一个元素1代替16成为了根结点,之后1下沉,14上移到堆顶(这个是算法导论中的分析,不一样的是这里是最大堆的堆排序过程)
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
参考代码:
//找出最小k个数.cpp#include <iostream>const int MAXLEN = 8;const int K = 4;using namespace std;//建立k个元素最大堆void HeapAdjust(int array[], int i, int Length){ int child,temp; for(temp = array[i]; 2*i+1 < Length; i = child) { child = 2 * i + 1; if(child < Length - 1 && array[child + 1] < array[child]) child ++; if(temp > array[child]) array[i] = array[child]; else break; array[child] = temp; }}//交换void Swap(int *a, int *b){ *a = *a ^ *b; *b = *a ^ *b; *a = *a ^ *b;}//得到最小int GetMin(int array[], int Length, int k){ int min = array[0]; Swap(&array[0], &array[Length - 1]); int child,temp; int i = 0,j = k-1; for(temp = array[0]; j > 0 && 2*i+1 < Length; --j,i = child) { child = 2*i+1; if(child < Length - 1 && array[child + 1] < array[child]) child++; if(temp > array[child]) array[i] = array[child]; else break; array[child] = temp; } return min;}void Kmin(int array[], int Length, int k){ for(int i = Length/2 - 1; i >= 0; --i) //初始建堆,时间复杂度为O(n) HeapAdjust(array, i, Length); int j = Length; for(int i = k; i > 0; --i,--j) //k次循环,每次循环的复杂度最多为k次交换,复杂度为O(k^2) { int min = GetMin(array,j,i); cout << min << endl; }}int main(){ int array[MAXLEN] = {13, 38, 49, 76, 97, 27, 65, 49}; //for(int i = MAXLEN; i > 0; --i) // array[MAXLEN - i] = i; Kmin(array, MAXLEN, K); return 0;}
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
思路四、类似快速排序的partition过程的分治算法
——《数据结构与算法分析--c语言描述》一书,第7章第7.7.6节中快速选择算法
1)类似快速排序的划分方法N个数存储在数组S中,再从数组中随机选取一个数X作为枢纽元,2)把剩下的数组划分为Sa和Sb两个部分,Sa<=X<=Sb,
3)如果要查找的k个元素小于等于Sa的元素个数,那么第k个最小元肯定在Sa中则返回Sa中较小的k个元素
4)否则第k个最小元在Sb中,返回Sa中所有元素+Sb中小的k-|Sa|个元素
参考代码:
//采用类似快速排序的partition过程的分治算法.cppvoid q_select(int a[], int k, int left, int right){ int i,j; int pivot; if(left + CUTOFF <= right) { pivot = median3(a,left,right);//取三个中值作为枢纽元 i = left; j = right - 1; for(; ;) { while(a[++i] < pivot); while(a[--j] > pivot); if(i < j) swap(&a[i], &a[j]); else break; } //重置枢纽元 swap(&a[i], &a[right-1]); if(k <= i) q_select(a, k, left, i - 1); else if(k > i+1) q_select(a, k, i+1, right); } else insert_sort(a + left, right - left + 1);}
注意:快速排序与快速选择一样,如果枢纽元选择不当,以至于S1或S2中有一个序列是空的,则依然会有最坏的运行时间O(N^2)的情况发生,上述使用三数中值作为枢纽元的方法可以避免这个情况发生,可以做到O(N)的复杂度
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
思路五、随机选取数列中的一个元素作为主元+遍历输出k个小的元素
——《算法导论》
每次都是随机选取数列中的一个元素作为主元,在O(n)的时间内找到第k小的元素,之后遍历输出前面的K个小的元素,比较一下熟知的快速排序,是以固定的第一个或最后一个元素作为主元,每次递归划分都是不均等的,最后的平均时间复杂度是O(nlogn)
思路六、五分化中项的中项法
——《算法导论》
像RANDOMIZED-SELECT一样,SELECTT通过输入数组的递归划分来找出所求元素,但是,该算法的基本思想是要保证对数组的划分是个好的划分。SECLECT采用了取自快速排序的确定性划分算法partition,并做了修改,把划分主元元素作为其参数
具体思路:
1)将输入数组的n个元素划分成n/5组,每组5个元素,且最后一个组存放n%5个元素。
2)寻找n/5个组中每一组的中位数,首先对每组中的元素(至多为5个)进行插入排序,之后选出中位数
3)对第2)步中找出的n/5个中位数,递归调用SELECT以找到其中位数x
4)按中位数的中位数x对输入数组进行划分,让k比划分低区的元素多1,所以x是第k小的元素,并且有n-k个元素在划分的高区
5)如果i = k,则返回x,否则如果i<k,在低区递归调用SELECT以找出第i小的元素;如果i>k,则在高区找第i-k个最小的元素。
- 寻找最小的k个数
- 寻找最小的k个数
- 寻找最小的K个数
- 寻找最小的k个数
- 寻找最小的K个数
- 寻找最小的k个数
- 寻找最小的k个数
- 寻找最小的k个数
- 寻找最小的k个数
- 寻找最小的k个数
- 寻找最小的k个数
- 寻找最小的k个数
- 寻找最小的 k 个数
- 寻找最小的k个数
- 寻找最小的k个数
- 寻找最小的k个数
- 寻找最小的k个数
- 寻找最小的K个数
- windows server 2003配置CA服务器通过SCEP颁发证书
- hdu 4911 Inversion(求逆序数)
- 连接池的优势
- adapter中加点击事件的一种写法
- u盘自动挂载-udev (转载加修改)
- 寻找最小的k个数
- 心态
- 计算机使用的一些技巧
- SSH 和 EasyUI结合的 combobox默认值问题解决方法
- java生成PFX证书
- LoadRunner关联详解
- jquery $(document).ready() 与window.onload的区别
- android解决无法设定listview的item高度
- python抓取网页的html