九度OJ 1371 最小的K个数 -- 堆排序
题目地址:http://ac.jobdu.com/problem.php?pid=1371
- 题目描述:
-
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
- 输入:
-
每个测试案例包括2行:
第一行为2个整数n,k(1<=n,k<=200000),表示数组的长度。
第二行包含n个整数,表示这n个数,数组中的数的范围是[0,1000 000 000]。
- 输出:
-
对应每个测试案例,输出最小的k个数,并按从小到大顺序打印。
- 样例输入:
-
8 4
-
4 5 1 6 2 7 3 8
- 样例输出:
-
1 2 3 4
我们可以先创建一个大小为k的数据容器来存储最小的k个数字。接下来我们每次从输入的n个整数中读入一个数。如果容器中已有的数字少于k个,则直接把这次读入的整数放入容器之中;如果容器中已有k个数字了,也就是容器已满,此时我们不能再插入新的数字而只能替换已有的数字。我们找出这已有的k个数中最大值,然和拿这次待插入的整数和这个最大值进行比较。如果待插入的值比当前已有的最大值小,则用这个数替换替换当前已有的最大值;如果带插入的值比当前已有的最大值还要大,那么这个数不可能是最小的k个整数之一,因为我们容器内已经有k个数字比它小了,于是我们可以抛弃这个整数。
因此当容器满了之后,我们要做三件事情:一是在k个整数中找到最大数,二是有可能在这个容器中删除最大数,三是可能要插入一个新的数字,并保证k个整数依然是排序的。如果我们用一个二叉树来实现这个数据容器,那么我们能在O(logk)时间内实现这三步操作。因此对于n个输入数字而言,总的时间效率就是O(nlogk)
下面是用堆排序解决该问题的代码:
#include <stdio.h> void HeapSort(int Array[], int len); void BuildMaxHeap(int Array[], int len); void ShiftDown(int Array[], int index, int len); void Swap(int *m, int *n); int main(void){ int len; int k; int Array[200000]; int i; while (scanf("%d %d", &len, &k) != EOF){ //读入数据个数 for (i=1; i<=len; ++i) //读入数据 scanf("%d", &Array[i]); BuildMaxHeap(Array, k); for (i=k + 1; i <= len; ++i){ if (Array[i] < Array[1]){ Array[1] = Array[i]; ShiftDown(Array, 1, k); } } HeapSort(Array, k); for (i=1; i<=k; ++i){ printf("%d", Array[i]); if (i != k) putchar (' '); } putchar ('\n'); } return 0; } void HeapSort(int Array[], int len){ int i; int time = len; for (i=0; i<len; ++i){ Swap(&Array[1], &Array[time]); --time; ShiftDown(Array, 1, time); } } void BuildMaxHeap(int Array[], int len){ int index = len/2; for (; index>0; --index){ ShiftDown(Array, index, len); } } void ShiftDown(int Array[], int index, int len){ while ((2*index) <= len || (2*index+1) <= len){ if (2*index+1 <= len){ if (Array[index] < Array[2*index] || Array[index] < Array[2*index+1]){ if (Array[2*index] > Array[2*index+1]){ Swap(&Array[index], &Array[2*index]); index = 2*index; } else{ Swap(&Array[index], &Array[2*index+1]); index = 2*index + 1; } } else break; } else{ if (Array[index] < Array[2*index]){ Swap(&Array[index], &Array[2*index]); index = 2*index; } else break; } } } void Swap(int *m, int *n){ //交换数据 int tmp; tmp = *m; *m = *n; *n = tmp; }
清橙OJ上相似的题目:http://blog.csdn.net/jdplus/article/details/19675351
九度OJ上相似的题目:http://blog.csdn.net/jdplus/article/details/19677345
参考资料:何海涛 -- 程序员面试题精选100题(05)-查找最小的k个元素[算法]