线性时间O(n)内求数组中第k大小的数
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线性时间O(n)内求数组中第k大小的数相关的知识,希望对你有一定的参考价值。
——本文为博主原创,转载请注明出处
因为最近做的WSN(wireless sensor network)实验要求用3个传感器节点接受2000个包的数据并算出一些统计量,其中就有算出中位数这么一个要求,且其按算出数据的时间长短排名给分,所以就在考虑一个线性时间的求第k大小的数的算法。
鉴于传感器只有10k的内存,以及考虑到快排的过程利于简化,所以采用快速排序(以及由之前课程中做的排序算法的测试得知,快排在相同时间复杂度的排序中有较大的优越性,最重要的就是快排好写)。
算法基本思想
快速排序的思想就不做过多的描述了,我们对之进行的改进是,每一趟划分过后,把我们要找的第k位与作为基准数的下标进行比较,如果k大,就在基准数右边的子数组中找,反之就在左边的子数组中找。这样就相当于每次快排过后对左右子数组的双递归被优化成了单侧的递归。
时间复杂度
考虑极端情况,假设数组大小n足够大,在查找的最后一趟(记为第m趟)才找到,第一趟没找到为O(n),第二趟没找到为O(n/2),第m趟没找到为O(n/2m-1),时间复杂度为O(n(1+1/2+....+1/2m-1)),其中1,1/2,....,1/2m-1为q小于1的等比数列,求和的值是个常数设为C(由∑1/2k的收敛性知),则O(n(1+1/2+....+1/2m-1))=O(nC)=O(n)
代码
因为传感器的代码需要用nesC写,所以程序采用C语言实现
1 #include <stdio.h> 2 3 int partition(int *a, int low, int high) 4 { 5 int pivot = a[low]; 6 while (low < high) 7 { 8 while (a[high] >= pivot && low < high) 9 high--; 10 a[low] = a[high]; 11 12 while (a[low] <= pivot && low <high) 13 low++; 14 a[high] = a[low]; 15 } 16 a[low] = pivot; 17 return low; 18 } 19 20 int quickSortKth(int *a, int low, int high, int k) 21 { 22 if (low >= high) 23 return a[low]; 24 else 25 { 26 int mid = partition(a, low, high); 27 if (mid > k) 28 quickSortKth(a, low, mid - 1, k); 29 else if (mid < k) 30 quickSortKth(a, mid + 1, high, k); 31 else 32 return a[mid]; 33 } 34 } 35 36 int getKthMax(int *a, int k, int len) { 37 return quickSortKth(a, 0, len - 1, len-k); 38 } 39 40 int getKthMin(int *a, int k, int len) { 41 return quickSortKth(a, 0, len - 1, k-1); 42 } 43 44 int main() 45 { 46 int a[15] = { 13,7,8,6,3,10,11,14,15,12,1,5,2,4,9 }; 47 int k; 48 int len = sizeof(a) / sizeof(a[0]);//获取数组a的大小 49 scanf("%d", &k); 50 //printf("%d", len); 51 printf("result: %d\\n", getKthMin(a, k, len)); 52 return 0; 53 }
结果
三花
2016-12-25
以上是关于线性时间O(n)内求数组中第k大小的数的主要内容,如果未能解决你的问题,请参考以下文章
Leetcode练习(python):第414题:第三大的数:给定一个非空数组,返回此数组中第三大的数。如果不存在,则返回数组中最大的数。要求算法时间复杂度必须是O(n)。