今天有人推荐了一个排序算法:最小堆排序算法。号称能处理10亿数据的排序问题.
正好将要面临2.5亿数据的查询计算比对问题,从没面对过如此大的数据量,之前处理过最大的表不过3000万,心里正有些惴惴不安。正好把这个算法拿来学习揣摩一番。
刚开始随手写了个递归排序,本以为想法是比对一下2种算法的,后来发现结果大跌眼镜。
下表中,表头是随机数量,内容单位为毫秒。
1000 | 10000 | 20000 | 100000 | 1000000 | 5000000 | 10000000 | 15000000 | 20000000 | |
最小堆排序算法 | 0 | 16 | 16 | 32 | 327 | 2137 | 4804 | 7675 | 10701 |
递归排序 | 16 | 172 | 718 | - | - | - | - | - | - |
自己写的递归算法只能给20000个随机数排序,超过就会引发java.lang.StackOverflowError异常,查了一下是jvm的堆栈溢出了,看来递归也不能随便用。。。。。。。
回到最关注的时间问题上,最小堆排序算法相当稳定,如果看折线图的话基本是条略上扬的斜线,1亿的随机数列也没问题,时间大概是70159毫秒,再多的数量考虑时间就没一一测试。
确实是个很好的算法,给将来的问题留了一条解决之路。
以下是代码
package algorithm; import java.util.Random; /******************************8 * 有十亿条数字,要从中选出最大的1000条,用什么算法最好? * 需要考虑空间复杂度和时间复杂度 * 其中10亿要表达的意思是,内存不能一次装下 * * 这个算法是“计算机科学中最重要的32个算法”之一 * * @author Administrator * */ public class 最小堆排序算法 { /* * 将数组调整为小根堆,即由小到大排序 */ public static int[] heap = new int[] { 1,3,7,3,5,2,8,4,6,10,9,11,54,23,13}; public static void initData(int n){ Random ran = new Random(); heap = new int[n]; for(int i=0;i<n;i++){ heap[i] = ran.nextInt(n*2); } } public static void main(String[] args) { initData(1*10000); long start = System.currentTimeMillis(); algorithm(); //custom(heap.length); long end = System.currentTimeMillis(); System.out.println("cost:"+(end-start)); show(); } /** * 展示排序结果 */ public static void show(){ StringBuffer sb = new StringBuffer(); for (int j = 0; j < heap.length; j++) { //System.out.print(heap[j] + " "); //sb.append(heap[j]+" "); } //System.out.println(sb.length()+","+sb.toString()); } /** * 自己定义的排序算法,主要用来比较时间 */ public static void custom(int end){ for(int i=0;i<end-1;i++){ if(heap[i]>heap[i+1]){ int temp = heap[i]; heap[i] = heap[i+1]; heap[i+1] = temp; } } if(end>1){ custom(end-1); } } /*** * 最小堆排序算法 */ public static void algorithm(){ int temp; /* * 创建堆(对该堆进行简单的排序) */ CreateHeap(); for (int i = heap.length - 1; 0 < i; i--) { temp = heap[0]; heap[0] = heap[i]; heap[i] = temp; /* //展示每次排序后的结果 for (int j = 0; j < heap.length; j++) { System.out.print(heap[j] + " "); } */ //System.out.println(i);//换行 //从堆顶进行调整,使未排序堆中最大关键字到堆顶 AdjustHeap(0,i); } } /* * 调整堆使其堆顶为未排序堆中最大关键字 */ public static void AdjustHeap(int location,int unSortlength) { int temp; int tempLoc; //确保左右节点存在 if ((tempLoc = (location + 1) * 2) < unSortlength) { //判断左右节点大小 if (heap[tempLoc] >= heap[tempLoc - 1]) { //判断父节点与子节点的大小,若父节点小,则与大的子节点换位 if (heap[location] < heap[tempLoc]) { temp = heap[location]; heap[location] = heap[tempLoc]; heap[tempLoc] = temp; //递归法对换位后的子节点及其子节点进行调整 AdjustHeap(tempLoc,unSortlength); } } else { //左节点大于右节点 if (heap[location] < heap[tempLoc - 1]) { temp = heap[location]; heap[location] = heap[tempLoc - 1]; heap[tempLoc - 1] = temp; //递归法对换位后的子节点及其子节点进行调整 AdjustHeap(tempLoc - 1,unSortlength); } } } //确保左节点存在 else if ((tempLoc = (location + 1) * 2 - 1) < unSortlength) { //与左节点进行比较 if (heap[location] < heap[tempLoc]) { //左子节点大于父节点,将两者进行换位 temp = heap[location]; heap[location] = heap[tempLoc]; heap[tempLoc] = temp; AdjustHeap(tempLoc,unSortlength); } } } /* * 创建堆(对该堆进行简单的排序) */ public static void CreateHeap() { for (int i = heap.length - 1; i >= 0; i--) { AdjustHeap(i,heap.length); } } }