线性时间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语言实现

 #include <stdio.h>

 int partition(int *a, int low, int high)
 {
     int pivot = a[low];
     while (low < high)
     {
         while (a[high] >= pivot && low < high)
             high--;
         a[low] = a[high];

         while (a[low] <= pivot && low <high)
             low++;
         a[high] = a[low];
     }
     a[low] = pivot;
     return low;
 }

 int quickSortKth(int *a, int low, int high, int k)
 {
     if (low >= high)
         return a[low];
     else
     {
         int mid = partition(a, low, high);
         if (mid > k)
             quickSortKth(a, low, mid - , k);
         else if (mid < k)
             quickSortKth(a, mid + , high, k);
         else
             return a[mid];
     }
 }

 int getKthMax(int *a, int k, int len) {
     , len - , len-k);
 }

 int getKthMin(int *a, int k, int len) {
     , len - , k-);
 }

 int main()
 {
     ] = { ,,,,,,,,,,,,,, };
     int k;
     ]);//获取数组a的大小
     scanf("%d", &k);
     //printf("%d", len);
     printf("result: %d\n", getKthMin(a, k, len));
     ;
 }

结果

线性时间O(n)内求数组中第k大小的数

线性时间O(n)内求数组中第k大小的数

线性时间O(n)内求数组中第k大小的数

线性时间O(n)内求数组中第k大小的数

三花

2016-12-25

上一篇:Struts2 学习笔记 09 访问Web元素


下一篇:Spring IOC (DI-依赖注入)