`
limitforest
  • 浏览: 10333 次
  • 性别: 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++、Java或其他编程语言编写的程序,这些程序是为了实现《编程珠玑》书中提到的各种算法和数据结构。源代码的学习对于理解书中的概念至关重要,因为它们提供了实际操作的例子,读者可以...

    编程珠玑 第二版 源代码

    《编程珠玑》第二版是计算机科学领域的一本经典著作,由Jon Bentley撰写,它以其深入浅出的方式探讨了程序设计中的诸多问题和解决方案。这本书不仅涵盖了算法和数据结构,还涉及了软件工程的实践与智慧,对于程序员...

    编程珠玑 第2版(修订版)_编程珠玑修订_资料_

    《编程珠玑》一书将这些技巧和经验整理成章,涵盖了算法、数据结构、性能优化、代码质量等多个方面,是程序员自我提升的重要参考资料。书中强调的问题求解策略和程序设计思想,对于初学者和资深开发者都有很大的启发...

    编程珠玑第二版及源代码

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

    编程珠玑源代码

    《编程珠玑》是计算机科学领域的一本经典著作,作者是Jon Bentley,它以其深入浅出的讲解方式,探讨了程序设计中的一些核心问题。这本书不仅涵盖了算法和数据结构,还涉及了问题解决、程序效率优化以及软件工程的...

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

    《编程珠玑》是一本经典的计算机科学与编程书籍,作者是Jon Bentley。这本书以其独特的视角深入探讨了程序设计的艺术和技巧,旨在提升程序员的问题解决能力,优化算法,并提高代码效率。书中涵盖了一系列实用的编程...

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

    每个`.cpp`文件都代表了《编程珠玑》中某一章节的C++代码实现,这为读者提供了一种实践和理解书中理论的途径。通过阅读和理解这些代码,读者不仅可以学习到编程技巧,还能体验到如何将理论知识应用到实际问题中,...

    《编程珠玑》源代码

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

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

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

    编程珠玑 Programming Pearls 第二版(中文版+源代码)

    《编程珠玑》是计算机科学领域的一本经典之作,作者是Jon Bentley,它以其独特的视角和深入浅出的讲解方式,向读者展示了编程艺术的精髓。这本书的第二版更是深受程序员和计算机科学家们的喜爱,因为它不仅涵盖了...

    编程珠玑第2版源代码

    此外,还可以通过对比不同栏目的代码实现,来领悟各种编程思想和技巧,提高自己的编程素养。 总之,这个压缩包为读者提供了一个极好的机会,能够直接接触到《编程珠玑》中所讲述的编程实践,加深对书中理论的理解,...

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

    "第二章questionC"提及的问题是关于"求变位词",这是一个常见的字符串处理问题,涉及到字符统计、排序以及字符串比较等基础知识。 变位词,又称为同字母异序词,是指两个或多个单词由完全相同的字母组成,但字母...

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

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

    编程珠玑pdf+源代码

    源码通常会涵盖一些经典的算法实现,比如排序算法的C++或Java版本,让读者能够直观地看到算法在实际代码中的应用。 5. **性能优化**:《编程珠玑》特别关注程序性能的优化,涵盖了内存管理、I/O操作和算法效率等...

    编程珠玑.pdf

    第一部分 编 程 技 术 第1章 性能监视工具 3 1.1 计算素数 3 1.2 使用性能监视工具 7 1.3 一个专用的性能监视工具 8 1.4 开发性能监视工具 10 1.5 原理 11 1.6 习题 11 1.7 深入阅读 12 第2章 关联数组 13 2.1 Awk中...

    编程珠玑 编程珠玑续

    《编程珠玑》和其续篇是两部深受程序员喜爱的经典著作,主要涵盖了程序设计、算法分析和数据结构等核心编程领域。这两本书以其深入浅出的讲解方式和丰富的实例,帮助读者提升编程技巧和解决问题的能力。 在《编程...

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

    《编程珠玑》是计算机科学领域的一本经典著作,作者是Jon Bentley,他在书中通过一系列有趣的问题和解决方案,深入浅出地探讨了程序设计的艺术和技巧。这本书的第二版中文PDF和源代码的提供,为中国的程序员和计算机...

    编程珠玑(第二版)答案

    根据提供的标题“编程珠玑(第二版)答案”和描述“编程珠玑(第二版)答案”,我们可以推测出这是关于《编程珠玑》这本书的相关解答资料。《编程珠玑》是一本经典的计算机科学书籍,作者为Jon Bentley。本书旨在...

Global site tag (gtag.js) - Google Analytics