最近,在看一本名爲《編程珠璣》的書,提升本身編寫代碼的能力和思路。裏面描述的都是用c或c++來寫,本身決定用java來實現裏面提到的一些思路。 這一章,講述如何在容量限制的範圍下,對數據量龐大,不會出現重複的隨機數據(整數)進行排序。如,用1MB的內存處理7位的整數。java
問題一:如何快速排序? 方法一:將整數一次讀入,進行屢次歸併排序。方法二:將整數分屢次讀入,多趟排序。方法三:也就是今天要講的重點,位圖或位向量集合排序。 先講講思路,用一個20位長的字符串表示一個全部元素都小於20的簡單的非負整數集合。例如,能夠用以下字符串來表示集合{1,2,3,5,8,13}: 0 1 1 1 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 表明集合中數值的位都置爲1,其餘的全部的位都置爲0; 所以,每一個7位的十進制整數表示一個小於1000萬的整數。c++
問題二:如何生成在n範圍內不重複的k個隨機數 思路,交換位置。先在r[0...n]中置爲各個值,值爲其下標值:a[i] = i 。而後在範圍(1,n)隨機產生一個正整數random,交換值r[1]與r[random];再在範圍(2,n)隨機產生另外一個正整數random,交換r[2]與r[random]....以此類推,一直循環k次。最後輸出前k項就是符合要求的隨機數。代碼以下:編程
<!--lang: java--> package ckj.chapter1; import java.io.BufferedWriter; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Random; public class RandomNumber { public static final int ARRAY_LENGTH = 3000000; private int size; private List<Integer> arrayList; @SuppressWarnings("unchecked") RandomNumber() { arrayList = new ArrayList<Integer>(); for (int i = 1; i <= ARRAY_LENGTH; i++) { arrayList.add(i); } } public RandomNumber(int size){ this(); this.size = size; } public List<Integer> generateRandNum() { Random r = new Random(); for (int i = 0; i < size; i++) { //System.out.println(Math.abs(r.nextInt(ARRAY_LENGTH))); int itemp = arrayList.get(i); int rtemp = Math.abs(r.nextInt(ARRAY_LENGTH-i)+i); //System.out.println("No. " + i + " random Number ---- > " + rtemp); arrayList.set(i, arrayList.get(rtemp)); arrayList.set(rtemp, itemp); } arrayList = arrayList.subList(0, size); return arrayList; } public static void print(Collection<Integer> array){ //System.out.println(); System.out.println(array); } public void writeFile(String fileName){ try { FileOutputStream fos = new FileOutputStream(fileName); OutputStreamWriter osw = new OutputStreamWriter(fos); BufferedWriter bw = new BufferedWriter(osw); String buf = arrayList.toString(); String tempbuf = buf.substring(1, buf.length()-1); bw.write(tempbuf); bw.flush(); bw.close(); osw.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args) { // TODO Auto-generated method stub int size = 50; RandomNumber rand = new RandomNumber(size); RandomNumber.print(rand.generateRandNum()); rand.writeFile("random.txt"); } }
下面,我分別用系統內部ArrayList提供的sort方法,TreeSet的排序集合 和 位排序 這三種方法比較。數組
首先,定義一個抽象類,名爲sort,用來記錄排序時間和從文件讀入隨機數。dom
<!-- lang: java --> package ckj.chapter1; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collection; import java.util.List; public abstract class Sort { public String sortName; public List<Integer> testArray; public Sort() { this.testArray = readFromFile("random.txt"); //RandomNumber.print(testArray); // System.out.println(testArray.size()); } private List<Integer> readFromFile(String fileName) { List<Integer> tempList = new ArrayList<Integer>(); try { FileInputStream fis = new FileInputStream(fileName); InputStreamReader isr = new InputStreamReader(fis); BufferedReader br = new BufferedReader(isr); String s; while ((s = br.readLine()) != null) { String temp = s; String[] arrayString = temp.split(", "); //System.out.println("SORT---->"+arrayString.length); for (int i = 0; i < arrayString.length; i++) { Integer in = new Integer(arrayString[i]); tempList.add(in.intValue()); //System.out.print(arrayString[i]+" "); } } br.close(); isr.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (NumberFormatException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return tempList; } public void sortTime() { long t1 = System.currentTimeMillis(); sort(); long costTime = System.currentTimeMillis() - t1; System.out.println("Time of " + sortName + " : " + costTime); } abstract public void sort(); public static void print(Collection<Integer> array){ System.out.println(array); } public void print(){ System.out.println(testArray); } }
而後,SetSort類實現sort的具體方法,調用Collecion.sort()方法。ide
<!-- lang: java --> import java.util.Collections; import ckj.chapter1.Sort; public class SetSort extends Sort { public SetSort(){ this.sortName = "SetSort"; } @Override public void sort() { // TODO Auto-generated method stub Collections.sort(testArray); } public static void main(String[] args){ Sort s = new SetSort(); s.sortTime(); }
}函數
TreeSort實現TreeSet類,其是自動排序的。不用調用任何方法。測試
<!-- lang: java --> package ckj.chapter1.treeset; import java.util.Set; import java.util.TreeSet; import ckj.chapter1.Sort; public class TreeSetSort extends Sort{ public Set<Integer> st; public TreeSetSort(){ this.sortName = "TreeSet" ; } @Override public void sort() { // TODO Auto-generated method stub st = new TreeSet<Integer>(this.testArray); } public void print(){ System.out.println(st); } }
最後是 BitSort,位排序,由於int是32位的,因此一個數組就能夠存32個數字位,因此生成一個size/32的數組,存放數據。調用set(),進行排序;test()方法是輸出。this
<!-- lang: java --> package ckj.chapter1.bitsort; import ckj.chapter1.RandomNumber; import ckj.chapter1.Sort; public class BitSort extends Sort { private int[] sortArray; public BitSort(){ this.sortName = "BitSort"; this.sortArray = new int[RandomNumber.ARRAY_LENGTH/32+1]; } private void set(int i){ this.sortArray[i>>5] |= (1 << ( i & 0x1f)); } private void clr(int i){ this.sortArray[i>>5] &= ~(1 << ( i & 0x1f)); } private int test(int i){ return (this.sortArray[i>>5] & (1 << (i & 0x1f))) ; } @Override public void sort() { // TODO Auto-generated method stub for ( int i = 0 ; i < RandomNumber.ARRAY_LENGTH ; i ++) clr(i); for ( int i = 0 ; i < this.testArray.size() ; i ++){ set(this.testArray.get(i)); } } public void print(){ for ( int i = 0 ; i < RandomNumber.ARRAY_LENGTH ; i ++) { if (test(i) != 0){ System.out.print(i+ " "); } } System.out.println(); } /*public static void main(String[] args){ Sort s = new BitSort(); s.sortTime(); s.print(); }*/ }
主函數MainClass調用測試代碼:code
<!-- lang: java --> package ckj.chapter1; import ckj.chapter1.bitsort.BitSort; import ckj.chapter1.setsort.SetSort; import ckj.chapter1.treeset.TreeSetSort; public class MainClass { private static final int _RANDOMSIZE = 1000000; /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub generateRandom(); Sort s = new SetSort(); s.sortTime(); //s.print(); s = new TreeSetSort(); s.sortTime(); //s.print(); s = new BitSort(); s.sortTime(); } private static void generateRandom() { RandomNumber rand = new RandomNumber(_RANDOMSIZE); //RandomNumber.print(rand.generateRandNum()); rand.generateRandNum(); rand.writeFile("random.txt"); } }
最後給一個測試結果,在3000000個範圍內,隨機產生不重複的1000000個正整數,運行時間比較:
<!-- lang: java --> Time of SetSort : 576 Time of TreeSet : 1537 Time of BitSort : 34
能夠看出,數據量越大,位排序的效果越好!又多了一種排序的思路了。