生活随笔
收集整理的這篇文章主要介紹了
【JAVA】大整数数据量排序
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
ZZ:http://pisces-java.iteye.com/blog/766745
?題目大意:移動公司需要對已經發放的所有139段的號碼進行統計排序,已經發放的139號碼段的文件都存放在一個文本文件中(原題是放在兩個文件中),一個號碼一行,現在需要將文件里的所有號碼進行排序,并寫入到一個新的文件中;號碼可能會有很多,最多可能有一億個不同的號碼(所有的139段號碼),存入文本文件中大概要占1.2G的空間;jvm最大的內存在300以內,程序要考慮程序的可執行性及效率;只能使用Java標準庫,不得使用第三方工具。?
??? 這是個典型的大數據量的排序算法問題,首先要考慮空間問題,一下把1.2G的數據讀入內存是不太可能的,就算把1一億條數據,轉都轉換成int類型存儲也要占接近400M的空間。當時做個題目我并沒有想太多的執行效率問題,主要就考慮了空間,而且習慣性的想到合并排序,基本思想是原文件分割成若干個小文件并排序,再將排序好的小文件合并得到最后結果,算法大概如下:?
??? 1.順序讀取存放號碼文件的中所有號碼,并取139之后的八位轉換為int類型;每讀取號碼數滿一百萬個(這個數據可配置)將已經讀取的號碼排序并存入新建的臨時文件。?
??? 2.將所有生成的號碼有序的臨時文件合并存入結果文件。?
??? 這個算法雖然解決了空間問題,但是運行效率極低,由于IO讀寫操作太多,加上步驟1中的排序的算法(快速排序)本來效率就不高(對于電話排序這種特殊情況來說),導致1億條數據排序運行3個小時才有結果。?
??? 如果和能夠減少排序的時間呢?首當其沖的減少IO操作,另外如果能夠有更加好排序算法也行。前天無聊再看這個題目時突然想到大三時看《編程珠璣》時上面也有個問題的需求這個這個題目差不多,記得好像使用是位向量(實際上就是一個bit數組),用電話作為index,心中大喜,找到了解決此問題的最完美方案啦:用位向量存儲電話號碼,一個號碼占一個bit,一億個電話號碼也只需要大概12M的空間;算法大概如下:?
????? 1.初始化bits[capacity];?
????? 2.順序所有讀入電話號碼,并轉換為int類型,修改位向量值:bits[phoneNum]=1;?
????? 3.遍歷bits數組,如果bits[index]=1,轉換index為電話號碼輸出。?
??? Java中沒有bit類型,一個boolean值占空間為1byte(感興趣的可以自己寫程序驗證),我自己寫個個用int模擬bit數組的類,代碼如下:?
public class BitArray {private int[] bits = null;private int length;//用于設置或者提取int類型的數據的某一位(bit)的值時使用private final static int[] bitValue = {0x80000000,//10000000 00000000 00000000 00000000 0x40000000,//01000000 00000000 00000000 00000000 0x20000000,//00100000 00000000 00000000 00000000 0x10000000,//00010000 00000000 00000000 00000000 0x08000000,//00001000 00000000 00000000 00000000 0x04000000,//00000100 00000000 00000000 00000000 0x02000000,//00000010 00000000 00000000 00000000 0x01000000,//00000001 00000000 00000000 00000000 0x00800000,//00000000 10000000 00000000 00000000 0x00400000,//00000000 01000000 00000000 00000000 0x00200000,//00000000 00100000 00000000 00000000 0x00100000,//00000000 00010000 00000000 00000000 0x00080000,//00000000 00001000 00000000 00000000 0x00040000,//00000000 00000100 00000000 00000000 0x00020000,//00000000 00000010 00000000 00000000 0x00010000,//00000000 00000001 00000000 00000000 0x00008000,//00000000 00000000 10000000 00000000 0x00004000,//00000000 00000000 01000000 00000000 0x00002000,//00000000 00000000 00100000 00000000 0x00001000,//00000000 00000000 00010000 00000000 0x00000800,//00000000 00000000 00001000 00000000 0x00000400,//00000000 00000000 00000100 00000000 0x00000200,//00000000 00000000 00000010 00000000 0x00000100,//00000000 00000000 00000001 00000000 0x00000080,//00000000 00000000 00000000 10000000 0x00000040,//00000000 00000000 00000000 01000000 0x00000020,//00000000 00000000 00000000 00100000 0x00000010,//00000000 00000000 00000000 00010000 0x00000008,//00000000 00000000 00000000 00001000 0x00000004,//00000000 00000000 00000000 00000100 0x00000002,//00000000 00000000 00000000 00000010 0x00000001 //00000000 00000000 00000000 00000001 };public BitArray(int length) {if(length < 0){throw new IllegalArgumentException("length必須大于零!");}bits = new int[length / 32 + (length % 32 > 0 ? 1 : 0)];//以整數來表示一個個bitthis.length = length;}//取index位的值public int getBit(int index){if(index <0 || index > length){throw new IllegalArgumentException("length必須大于零小于" + length);}int intData = bits[index/32];return (intData & bitValue[index%32]) >>> (32 - index%32 -1);}//設置index位的值,只能為0或者1public void setBit(int index,int value){if(index <0 || index > length){throw new IllegalArgumentException("length必須大于零小于" + length);} if(value!=1&&value!=0){throw new IllegalArgumentException("value必須為0或者1");}int intData = bits[index/32];if(value == 1){bits[index/32] = intData | bitValue[index%32];}else{bits[index/32] = intData & ~bitValue[index%32];}}public int getLength(){return length;}
}
bit數組有了,剩下就是算法代碼,核心代碼如下:?
?
bitArray = new BitArray(100000000); //順序讀取所有的手機號碼while((phoneNum = bufferedReader.readLine())!=null){phoneNum = phoneNum.trim().substring(3);//13573228432//取139后8位轉換為int類型phoneNumAsInt = Integer.valueOf(phoneNum);//設置對應bit值為1bitArray.setBit(phoneNumAsInt, 1);} //遍歷bit數組輸出所有存在的號碼for(int i = 0;i<sortUnit;i++){if(bitArray.getBit(i)==1){writer.write("139" + leftPad(String.valueOf(i + sortUnit*times), 8));writer.newLine(); } }writer.flush();
?
?經測試,修改后的算法排序時只需要20多M的內存,一億條電話號碼排序只要10分鐘(時間主要花在IO上),看來效果還是很明顯的。?
??? 這個算法很快,不過也有他的局限性:?
??? 1.只能用于整數的排序,或者可以準確映射到正整數(對象不同對應的正整數也不相同)的數據的排序。?
??? 2.不能處理重復的數據,重復的數據排序后只有一條(如果有這種需求可以在這個算法的基礎上修改,給出現次數大于1的數據添加個計數器,然后存入Map中)?
??? 3.對于數據量極其大的數據處理可能還是比較占用空間,這種情況可配合多通道排序算法解決。?
??? PS:這個算法的思想源于《編程珠璣》,有興趣的可以讀讀那本書,非常不錯!?
轉載于:https://www.cnblogs.com/lqminn/archive/2012/08/30/2663281.html
總結
以上是生活随笔為你收集整理的【JAVA】大整数数据量排序的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。