《编程珠玑》第一章:开篇——排序

最近,在看一本名为《编程珠玑》的书,提高自己编写代码的能力和思路。里面描述的都是用c或c++来写,自己决定用java来实现里面提到的一些思路。 这一章,讲述如何在容量限制的范围下,对数据量庞大,不会出现重复的随机数据(整数)进行排序。如,用1MB的内存处理7位的整数。

问题一:如何快速排序? 方法一:将整数一次读入,进行多次归并排序。方法二:将整数分多次读入,多趟排序。方法三:也就是今天要讲的重点,位图或位向量集合排序。 先讲讲思路,用一个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万的整数。

问题二:如何生成在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,用来记录排序时间和从文件读入随机数。

<!-- 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()方法。

<!-- 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()方法是输出。

<!-- 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调用测试代码:

<!-- 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

可以看出,数据量越大,位排序的效果越好!又多了一种排序的思路了。

转载于:https://my.oschina.net/gzckj/blog/89098

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值