`
limitforest
  • 浏览: 10103 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

《编程珠玑》第一章Java代码实现

阅读更多
我看算法的时候只看伪代码的话,感觉太抽象,总记不住,我希望能看到真正实现的代码,这样心里会感觉踏实一点。

因此,总希望能把书上的算法给具体实现了,这样一来能记住算法,加深印象,而来二来也能提高自己的编程水平。

《编程珠玑》的代码已经有C/C++的实现版本了,我在附件也贴出来了,但是,作为一个C++语言的入门者,因为还涉及到不知道如何链接C++的函数库等种种问题,一直都没法编译运行,非常郁闷。于是,产生了一个想法,用我比较擅长的Java语言把书上的算法实现。以后分几章贴出我的代码,希望牛人点评指正。

第一章《开篇》, 很经典,特别是位图法经典的经典。

它就提出了这样一个问题,如何对一个磁盘文件进行排序。这个文件之多包含10000000(7个0)条记录,每条记录是一个不超过7位的整数。

该问题还有一个限制的条件,只有1MB的可用主存,磁盘空间充足。在这里我采用java的虚拟机变量来模拟,这里采用-Xms2M(初始的内存数) -Xmx2M(最大的内存数)来限制。

再解这个问题之前,还需要解决一个问题,那就需要一个输入文件,包含了10000000条记录,而且最好是每条记录都不同。

解决这个问题的办法再编程珠玑第12章给出来了。以下贴出代码。


/**
 * 随机产生1-n的m个数
 * 
* 
*/
public class RandomGenerate {
 public static void main(String[] args) {
 if (args.length == 0) {
 System.out.println("useage: java com.ch12.RandomGenerate 70000000 10000000 ");
 //f1(20, 100);
 //f0(m, n); 
return;
 }
 int m = Integer.parseInt(args[0]);
 int n = Integer.parseInt(args[1]);
 System.out.println("m:" + m + ",n:" + n);
 long l1 = System.currentTimeMillis();
 try {
 PrintWriter pw = new PrintWriter("d:/input.txt");
 f1(m, n, pw);
 pw.close();
 } catch (FileNotFoundException e) {
 e.printStackTrace();
 }
 long l2 = System.currentTimeMillis();
 System.out.println("time:" + (l2 - l1));
 
}
 
static int randInt(int i, int j, Random rand) {
 if (i < j)
 return i + rand.nextInt(j - i + 1);
 else if (i > j)
 return j + rand.nextInt(i - j + 1);
 return i;
 }
 
static void f0(int m, int n) {
 int select = m;
 int remaining = n;
 Random rand = new Random(System.currentTimeMillis());
 for (int i = 0; i < n; i++) {
 if (rand.nextInt(remaining) < select) {
 System.out.println(m - select + 1 + ":" + i);
 select--;
 }
remaining--;
 }
 
}
 
static void f1(int m, int n) {
 int[] array = new int[n];
 Random rand = new Random(System.currentTimeMillis());
 for (int i = 0; i < n; i++)
 array[i] = i + 1;
 for (int i = 0; i < m; i++) {
 int j = randInt(i, n - 1, rand);
 int temp = array[j];
 array[j] = array[i];
 array[i] = temp;
 }
 
for (int i = 0; i < m; i++) {
 System.out.println(i + 1 + ":" + array[i]);
 }
 }
 
static void f1(int m, int n, PrintWriter pw) {
 int[] array = new int[n];
 Random rand = new Random(System.currentTimeMillis());
 for (int i = 0; i < n; i++)
 array[i] = i + 1;
 for (int i = 0; i < m; i++) {
 int j = randInt(i, n - 1, rand);
 int temp = array[j];
 array[j] = array[i];
 array[i] = temp;
 }
 
for (int i = 0; i < m; i++) {
 pw.println(array[i]);
 
}
 pw.flush();
 }
 
}

方法1 位图法 主要是使用Java中的BitSet类来实现,我看了BitSet的源码,它内部也是用数组来实现的。

/**
 * 采用位图法
 *
 */
public class BitSort1 {
 
/**
 * @param args
 */
 public static void main(String[] args) {
 if (args.length < 1) {
 System.out.println("usage: java -Xms2M -Xmx2M com.ch1.BitSort1 d:\\input.txt d:\\output.txt");
 return;
 }
 
try {
 BitSort1 client = new BitSort1();
 BufferedReader br = new BufferedReader(new FileReader(args[0]));
 PrintWriter pw = new PrintWriter(args[1]);
 long l1 = System.currentTimeMillis();
 client.input(br);
 client.output(pw);
long l2 = System.currentTimeMillis();
 System.out.println("time:" + (l2 - l1));
 } catch (FileNotFoundException e) {
 e.printStackTrace();
 }
 
}
 
BitSet bs = new BitSet(10 ^ 7);
 
void input(BufferedReader br) {
 String s = "";
 try {
 while ((s = br.readLine()) != null) {
 int in = Integer.parseInt(s);
 bs.set(in);
 }
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
 
 
 
void output(PrintWriter pw) {
 int size = bs.size();
 for (int i = 0; i < size; i++) {
 if (bs.get(i)) {
 pw.println(i);
 }
 }
 pw.flush();
 }
 
}

方法2 硬盘排序法 首先将数据分成n份,如1-249999是第一份,250000到499999是第二份,以此类推,然后对每一份文件用系统排序,然后把它输出。

/**
 * 采用硬盘排序
 *
 */
public class BitSort2 {
 
/**
 * @param args
 */
 public static void main(String[] args) {
 if (args.length < 1) {
 System.out.println("usage: java -Xms2M -Xmx2M com.ch1.BitSort3 d:\\input.txt d:\\output.txt");
 return;
 }
 
BitSort2 client = new BitSort2();
 long l1 = System.currentTimeMillis();
 
client.fun(args[0], args[1]);
 
long l2 = System.currentTimeMillis();
 System.out.println("time:" + (l2 - l1));
 
}
 
public final static int SIZE = 10000000; //总大小
 public final static int TIMES = 40; //次数
 public final static int UNIT = SIZE / TIMES;
 
void fun(String inputName, String outputName) { 
try {
 PrintWriter pw = new PrintWriter(outputName);

 for (int index = 0; index < TIMES; index++) {
 BufferedReader br = new BufferedReader(new FileReader(inputName));
 int low = UNIT * index, high = low + UNIT;
 int[] arr = new int[UNIT];
 int counter = 0;
 String s = "";
 while ((s = br.readLine()) != null) {
 int in = Integer.parseInt(s);
 if (in > low && in <= high) {
 arr[counter++] = in;
 }
 }
 arr = Arrays.copyOf(arr, counter); 
Arrays.sort(arr);
 int size = arr.length;
 for (int i = 0; i < size; i++) {
 pw.println(arr[i]);
 }
 pw.flush();
 br.close();
 }
 pw.close();
 } catch (FileNotFoundException e) {
 e.printStackTrace();
 } catch (IOException e) {
 e.printStackTrace();
 }
 
}

方法3 基于磁盘的多路归并排序 首先把大文件平均分成n份,然后每一份都排好序,然后建一个n个数的堆,每次从堆中取出最小的数,取完之后从取走的那个数的那个文件取下一个数,如果这个文件没有数了,则取它的下一个文件的数,直到所有的文件都取完时,再把堆中的数都输出。

/**
 * 采用外部排序 基于磁盘的多路归并排序
 */
public class BitSort4 {
 
/**
 * @param args
 */
 public static void main(String[] args) {
 if (args.length < 1) {
 System.out.println("usage: java -Xms2M -Xmx2M com.ch1.BitSort4 d:\\input.txt d:\\output.txt");
 return;
 }
 
BitSort4 client = new BitSort4();
 long l1 = System.currentTimeMillis();
 
client.fun(args[0], args[1]);
 
long l2 = System.currentTimeMillis();
 System.out.println("time:" + (l2 - l1));
 
}
 
public final static int SIZE = 10000000; //总大小
 public final static int TIMES = 80; //次数
 public final static int UNIT = SIZE / TIMES;
 
int[] heap = new int[TIMES + 1]; //堆
 int[] indexs = new int[TIMES + 1]; //索引
 boolean[] isNulls = new boolean[TIMES];
 //int[] nums = new int[TIMES];
 
void fixUp(int k) {
 int j = 0;
 while ((j = k >> 1) > 0) {
 if (heap[k] >= heap[j])
 break;
 int temp = heap[j];
 heap[j] = heap[k];
 heap[k] = temp;
 
temp = indexs[j];
 indexs[j] = indexs[k];
 indexs[k] = temp;
 
k = j;
 }
 }
 
void fixDown(int k) {
 int size = TIMES;
 int j = 0;
 while ((j = k << 1) <= size && j > 0) {
 if (j + 1 <= size && heap[j + 1] <= heap[j])
 j++;
 if (heap[k] <= heap[j])
 break;
 int temp = heap[j];
 heap[j] = heap[k];
 heap[k] = temp;
 
temp = indexs[j];
 indexs[j] = indexs[k];
 indexs[k] = temp;
 
k = j;
 }
 }
 
void fixDown(int k, int size) {
 int j = 0;
 while ((j = k << 1) <= size && j > 0) {
 if (j + 1 <= size && heap[j + 1] <= heap[j])
 j++;
 if (heap[k] <= heap[j])
 break;
 int temp = heap[j];
 heap[j] = heap[k];
 heap[k] = temp;
 
temp = indexs[j];
 indexs[j] = indexs[k];
 indexs[k] = temp;
 
k = j;
 }
 }
 
void add(int index, int val) {
 indexs[1] = index;
 heap[1] = val;
 fixDown(1);
 }
 
int getMin() {
 return heap[1];
 }
 
int getWhich() {
 return indexs[1];
 }
 
void fun(String inputName, String outputName) {
 try {
 
PrintWriter[] pws = new PrintWriter[TIMES];
 for (int i = 0; i < TIMES; i++) {
 pws[i] = new PrintWriter("temp\\temp" + i + ".txt");
 }
 
BufferedReader br = new BufferedReader(new FileReader(inputName));
 String s = "";
 int index = 0;
 while ((s = br.readLine()) != null) {
 int in = Integer.parseInt(s);
 PrintWriter pwt = pws[index % TIMES];
 pwt.println(in);
 pwt.flush();
 index++;
 }
 
br.close();
 
for (int i = 0; i < TIMES; i++) {
 pws[i].close();
 }
 
for (int i = 0; i < TIMES; i++) {
 BufferedReader brt = new BufferedReader(new FileReader("temp\\temp" + i + ".txt"));
 index = 0;
 int[] arr = new int[UNIT];
 while ((s = brt.readLine()) != null) {
 int in = Integer.parseInt(s);
 arr[index++] = in;
 }
 arr = Arrays.copyOf(arr, index);
 Arrays.sort(arr);
 PrintWriter pwt = new PrintWriter("temp\\temptemp" + i + ".txt");
 int size = arr.length;
 for (int j = 0; j < size; j++) {
 pwt.println(arr[j]);
 }
 brt.close();
 pwt.close();
 new File("temp\\temp" + i + ".txt").delete();
 new File("temp\\temptemp" + i + ".txt").renameTo(new File("temp\\temp" + i + ".txt"));
 }
 
//System.out.println("--------------------------");
 
PrintWriter pw = new PrintWriter(outputName);
 
//建堆
BufferedReader[] brs = new BufferedReader[TIMES];
 for (int i = 0; i < TIMES; i++) {
 brs[i] = new BufferedReader(new FileReader("temp\\temp" + i + ".txt"));
 int in = Integer.parseInt(brs[i].readLine());
 heap[i + 1] = in;
 indexs[i + 1] = i;
 }
 for (int i = 2; i <= TIMES; i++) {
 fixUp(i);
 }
 String st = "";
 boolean flag = false;
 while (true) {
 int in = getMin();
 pw.println(in);
 int which = getWhich();
 int orgin = which;
 
st = null;
 if (!isNulls[which]) {
 st = brs[which].readLine();
 //nums[which]++;
 if (st == null) {
 //System.out.println(which + ":" + nums[which]);
 isNulls[which] = true;
 }
 }
 while (isNulls[which]) {
 which++;
 which = which % TIMES;
 
if (which == orgin) {
 //System.out.println("orgin:" + orgin);
 flag = true;
 break;
 }
 if (!isNulls[which]) {
 st = brs[which].readLine();
 //nums[which]++;
 if (st == null) {
 //System.out.println(which + ":" + nums[which]);
 isNulls[which] = true;
 }
 }
 }
 
if (flag)
 break;
 
int val = Integer.parseInt(st);
 add(which, val);
 }
 
//将堆中剩余的元素按顺序输出
int size = TIMES;
 heap[1] = heap[size];
 size--;
fixDown(1, size);
 //System.out.println(Arrays.toString(heap));
 while (size > 0) {
 int in = getMin();
 pw.println(in);
 
heap[1] = heap[size];
 size--;
fixDown(1, size);
 }
 
pw.flush();
 pw.close();
 //System.out.println(Arrays.toString(nums));
 //System.out.println(Arrays.toString(isNulls));
 } catch (FileNotFoundException e) {
 e.printStackTrace();
 } catch (IOException e) {
 e.printStackTrace();
 }
 
}
 
}
分享到:
评论

相关推荐

    《编程珠玑》部分源代码Java实现

    这是《编程珠玑》上用Java实现的源代码,只有几章,其中第一章则较完整把几种方法如位图、归并排序等都实现了。

    编程珠玑源码下载编程珠玑书后源代码

    编程珠玑书后源代码编程珠玑书后源代码编程珠玑书后源代码编程珠玑书后源代码编程珠玑书后源代码编程珠玑书后源代码

    编程珠玑第二版及源代码

    编程珠玑第二版及源代码实现(C/C++) 如果让程序员们列举他们喜欢的书籍,Jon Bentley的《编程珠玑》一定可以归于经典之列。如同精美的珍珠出自饱受沙砾折磨的牡蛎,程序员们的精彩设计也来源于曾经折磨他们的实际...

    编程珠玑 编程珠玑 编程珠玑 编程

    我觉得不错,和大家分享! 编程珠玑 编程珠玑 编程珠玑

    编程珠玑源代码

    编程珠玑源代码还有课后习题代码,官方版本

    编程珠玑编程珠玑

    编程珠玑编程珠玑

    编程珠玑之第二章questionC 测试数据

    本资源只是“编程珠玑之第二章questionC: 求变位词问题”的简单的测试数据。

    《编程珠玑》源代码

    《编程珠玑》第一版是我早期职业生涯中阅读过的对我影响较大的书籍之一,在书中首次接触到的很多观点都让我长期受益。作者在这一版本中做了重要更新。新增加的很多例子让我耳目一新。 ——Steve McConnell,《代码...

    编程珠玑(第二版)源代码

    编程珠玑 本书针对程序设计人员探讨了一系列的实际问题,这些问题... 本书在第一版的基础上增加了3个方面的新内容:测试、调试和计量,集合表示,字符串问题,并对第一版的所有程序都进行了改写,生成了等量的新代码。

    编程珠玑 第二版 源代码

    不用说了,经典中的经典,自己下载后看看就知道了………………………………………………………………………………………………………………………………………………

    《编程珠玑》(Programming Pearls)课本和习题代码实现

    《编程珠玑》(Programming Pearls)课本和习题C++代码实现,包括基本所有课本讲解内容的代码实现,以及大量课后习题的实现。

    编程珠玑 java程序员应该读的书籍

    编程珠玑 java程序员应该读的书籍,好好的读了,很有帮助的了

    编程珠玑pdf+源代码

    编程珠玑源码 IT大公司面试必看数据 计算机专业必看经典教材

    编程珠玑 编程珠玑续

    编程珠玑和编程珠玑续两本,上传赚点分,填充填充填充

    编程珠玑(续)

    《编程珠玑(续)》是计算机...书中涵盖了程序员操纵程序的技术、程序员取舍的技巧、输入和输出设计以及算法示例,这些内容组成一个有机的整体,如一串串珠玑展示给程序员。  《编程珠玑(续)》适合各级程序员阅读参考。

    《编程珠玑》第2版中文PDF+源代码

    《编程珠玑》第2版中文PDF+源代码,仅仅用于个人学习,传播获利违法

    编程珠玑及其源码

    编程珠玑,编程珠玑续以及源码,本书针对程序设计人员探讨了一系列的实际问题,这些问题是对现实中常见问题的归纳总结。作者虽然没有给出解决这些问题的具体代码,但始终非常富有洞察力和创造力地围绕着这些折磨...

    编程珠玑(第二版)答案

    编程珠玑(第二版)答案

    编程珠玑 第二版 中文版 英文版

    编程珠玑 第二版 中文版 英文版 大家可以看看 还附有源代码哦!

Global site tag (gtag.js) - Google Analytics