ldjhust

工欲善其事 必先利其器

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

输入n 个整数,输出其中最小的k 个。

例如输入1,2,3,4,5,6,7 和8 这8 个数字,则最小的4 个数字为1,2,3 和4。

经典的TopK问题,因为需要最小的K个元素,所以只需创建并维持一个拥有K个元素的最大堆即可。

创建一个拥有K个元素的最大堆的代码为:

 1 void CreateMaxHeap(int *MaxHeap, int K)
 2 {
 3     assert (MaxHeap != NULL);
 4 
 5     assert (K > 0);
 6 
 7     // 从最后一个有子孩子的节点开始往下调整,一直到根节点,则这个最大堆就创建好了
 8     for (int i = (K >> 1) - 1; i >= 0; --i)
 9     {
10         MaxHeapFixDown (MaxHeap, i, K);
11     }
12 }

向下调整最大堆得函数代码为:

 1 void MaxHeapFixDown(int *MaxHeap, int l, int K)
 2 {
 3     assert (MaxHeap != NULL);
 4 
 5     assert (l >= 0);
 6 
 7     assert (l < K);
 8 
 9     int nTemp = MaxHeap[l];
10     int i = l;
11     int j = 2 * i + 1;
12 
13     while (j < K)
14     {
15         if (((j + 1) < K) && (MaxHeap[j+1] > MaxHeap[j]))
16         {
17             // 获取两个子孩子中值最大的那个
18             ++j;
19         }
20 
21         if (MaxHeap[j] <= nTemp)
22         {
23             // 如果最大的子孩子都小与nTemp,则nTemp的正确位置就是这两个孩子父亲的位置
24             break;
25         }
26 
27         // 大值往上冒
28         MaxHeap[i] = MaxHeap[j];
29         i = j;
30         j = 2 * i + 1;
31     }
32 
33     // 确定nTemp的正确位置
34     MaxHeap[i] = nTemp;
35 }

  基于上,我们只需将数组的前K个元素调整成最大堆,然后从第K+1个元素开始与最大堆的根节点比较(最大堆的根节点是堆中的最大值),若比最大值小,则需将这个元素与堆的根节点交换位置,然后调整这个最大堆,反之则不需做任何处理,一直到数组中第N个元素。最后数组中最小的K个元素就是数组的前K个元素,直接将其输出即可。

  基于上述分析,获取最小K个元素的代码如下:

 1 void GetKMinNumber(int *a, int N, int K)
 2 {
 3     assert (a != NULL);
 4 
 5     assert (K > 0);
 6 
 7     assert (K <= N);
 8 
 9     if (K == N)
10     {
11         // 最小的K歌元素就保存在数组a的前K个数据块中
12         cout << "最小的 " << K << " 个元素为: ";
13         for (int i = 0; i < K; ++i)
14         {
15             cout << a[i] << " ";
16         }
17 
18         cout << endl;
19 
20         return;
21     }
22 
23     // 创建一个最大堆
24     CreateMaxHeap (a, K);
25 
26     for (int i = K; i < N; ++i)
27     {
28         if (a[i] < a[0])
29         {
30             Swap (a[i], a[0]);
31 
32             // 更新一个元素后就要维护这个堆,使其保持为最大堆
33             MaxHeapFixDown (a, 0, K);
34         }
35     }
36 
37     // 最小的K歌元素就保存在数组a的前K个数据块中
38     cout << "最小的 " << K << " 个元素为: ";
39     for (int i = 0; i < K; ++i)
40     {
41         cout << a[i] << " ";
42     }
43 
44     cout << endl;
45 }

  给出一个测试结果如下:

posted on 2013-04-30 15:42  ldjhust  阅读(435)  评论(0编辑  收藏  举报