在100W个数中获得最大/小的50个数
来源:互联网 发布:飞鱼直播软件下载 编辑:程序博客网 时间:2024/05/24 07:25
前年有个朋友在南大考研复试时被老师一个题目问住了,“如何在100W个数中选最大/小的50个?”当时他的回答是快速排序。那么快排的平均比较次数是m*nlogn(log以2为底,m是个常数),所以总共的比较次数大约是100W*20m(2的10次方大约为1000,所以2的20次方大约是100W)。
当时我的想法是用插入排序维护1个容量为50的数组。这个数组保存着最小的50个数,每次比较都把最大的那个数给抛弃。当随着比较次数的增多,从概率上讲,越到后面的元素越有可能只需比较1次(因为这个数会比数组中最大的数更大)。但因为这个涉及到概率问题,所以很难计算平均比较次数。但可以算得最坏比较次数大约是50*100W,即5000W次。当时也懒得实验一下我的想法效果如何,就没继续实验了。
后来,有个两个同学告诉我正确解法应该是堆排序。构建好初始堆后每次取出最小的数最多只需log(n)的比较,所以总共比较次数不会大于m*50*log(100W),即m*50*20=1000次(其实最后一次取出最小元素无需再维护堆这个数据结构,实际上应该是49*20*m次)。但是他们忽略了一点,构建初始堆的复杂度为O(N),所以实际上总的比较次数应该是s*100W+1000*m(s和m是常数)。
当然,如果直接暴力点用选择排序的变形也是可以的。用选择排序直接选出最小的50个,比较次数为(100w-1)+(100w-2)+...+100w(-50),省略后面一堆尾巴,最后比较次数大约是5000w次。
前段时间由于需要完成一个TOP K的功能,所以封装了一个TOP K的数据结构(class TopK<T>,即用插入排序维护一个容量为K的数组,这个数组保存的是最大或最小的K个元素。T是泛型)。今天正好来验证我当时的想法。不过效果很不理想,我猜测是频繁类型转换以及拆箱装箱导致的。(使用时只能用TopK<Integer>。由于JAVA的泛型和C++以及C#的泛型不同,JAVA的泛型其实就是Object+自动类型转换)。最后不使用封装重新写了一遍这个数据结构,效果好了许多。
至于堆排序,本来使用JAVA自带的优先队列PriorityQueue。效果差得令人发指。我稍微看了下源代码,也没搞懂为什么会这么慢。感觉即使是频繁的类型转换和拆箱装箱也不应该差这么多。最后从网上找了堆排序,效果挺好。(我一开始就指定了优先队列的容量,所以不是扩容的问题)
以下是实验结果,第一幅图是100W数据的实验结果,第二幅是1000W数据的实验结果。
当时我的想法是用插入排序维护1个容量为50的数组。这个数组保存着最小的50个数,每次比较都把最大的那个数给抛弃。当随着比较次数的增多,从概率上讲,越到后面的元素越有可能只需比较1次(因为这个数会比数组中最大的数更大)。但因为这个涉及到概率问题,所以很难计算平均比较次数。但可以算得最坏比较次数大约是50*100W,即5000W次。当时也懒得实验一下我的想法效果如何,就没继续实验了。
后来,有个两个同学告诉我正确解法应该是堆排序。构建好初始堆后每次取出最小的数最多只需log(n)的比较,所以总共比较次数不会大于m*50*log(100W),即m*50*20=1000次(其实最后一次取出最小元素无需再维护堆这个数据结构,实际上应该是49*20*m次)。但是他们忽略了一点,构建初始堆的复杂度为O(N),所以实际上总的比较次数应该是s*100W+1000*m(s和m是常数)。
当然,如果直接暴力点用选择排序的变形也是可以的。用选择排序直接选出最小的50个,比较次数为(100w-1)+(100w-2)+...+100w(-50),省略后面一堆尾巴,最后比较次数大约是5000w次。
前段时间由于需要完成一个TOP K的功能,所以封装了一个TOP K的数据结构(class TopK<T>,即用插入排序维护一个容量为K的数组,这个数组保存的是最大或最小的K个元素。T是泛型)。今天正好来验证我当时的想法。不过效果很不理想,我猜测是频繁类型转换以及拆箱装箱导致的。(使用时只能用TopK<Integer>。由于JAVA的泛型和C++以及C#的泛型不同,JAVA的泛型其实就是Object+自动类型转换)。最后不使用封装重新写了一遍这个数据结构,效果好了许多。
至于堆排序,本来使用JAVA自带的优先队列PriorityQueue。效果差得令人发指。我稍微看了下源代码,也没搞懂为什么会这么慢。感觉即使是频繁的类型转换和拆箱装箱也不应该差这么多。最后从网上找了堆排序,效果挺好。(我一开始就指定了优先队列的容量,所以不是扩容的问题)
以下是实验结果,第一幅图是100W数据的实验结果,第二幅是1000W数据的实验结果。
快速排序用的是JAVA自带的Arrays.sort。效果不好可能是频繁的递归以及赋值花销过大。实验证明,我的算法比较次数大概是1.015*n,而堆排序大概是1.882*n。至于交换次数,我的方法比堆排序不在一个数量级上。
0 0
- 在100W个数中获得最大/小的50个数
- 100w个数中找出最大的k个数
- 100w个数中找出最大的前k个数
- 100w个数中找出最大的前K个数
- 在100w个数中找最大的前100个数
- 百度面试题:在100w个数中找最大的前100个数
- 在100w个数中找最大的前100个数
- 在100w个数中找最大的前100个数
- 面试练习题-100w个数中找出最大的100个数
- 在m个数中寻找最大的n个数
- TopK问题--100W个数种找出其中最大的前K个数;
- 在存有10亿个数的文件中找到最大的100万个数
- 最大 / 小的K个数
- 100万个数中找到最大的100个数
- 100万个数中找出最大的前100个数
- N个数中选出最大(小)的n个数
- 求100W个数中的前K个最大的数
- 在无序数组中取最大的K个数
- 实验室第五周周工作总结
- 史上最全的CSS hack方式一览
- Objective-C实现单例模式
- Wrapper cannot find servlet class CounterServlet or a class it depends on
- 矩阵斜着输出并且从下到上
- 在100W个数中获得最大/小的50个数
- hdu 5067 遍历指定点集最小时间
- Head First设计模式之观察者,装饰者模式
- 使用灰度共生矩阵实现指纹分割
- POJ 1470 LCA tarjan 离线算法
- Struts2中过滤器和拦截器的区别
- Android线程池使用终结版
- Gadfly 画图-Julia编程
- objective-C原生态的同步请求和异步请求实例