《編程珠璣》第一章:開篇——排序

最近,在看一本名爲《編程珠璣》的書,提升本身編寫代碼的能力和思路。裏面描述的都是用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

能夠看出,數據量越大,位排序的效果越好!又多了一種排序的思路了。

相關文章
相關標籤/搜索