我看算法的时候只看伪代码的话,感觉太抽象,总记不住,我希望能看到真正实现的代码,这样心里会感觉踏实一点。
因此,总希望能把书上的算法给具体实现了,这样一来能记住算法,加深印象,而来二来也能提高自己的编程水平。
《编程珠玑》的代码已经有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实现源代码是一个宝贵的教育资源,它将理论知识与实际代码相结合,是提升编程思维和实战能力的理想资料。通过深入研究这些代码,你将不仅能够解决书中的问题,还能将这些智慧应用到自己...
"源代码" 文件通常包含C、C++、Java或其他编程语言编写的程序,这些程序是为了实现《编程珠玑》书中提到的各种算法和数据结构。源代码的学习对于理解书中的概念至关重要,因为它们提供了实际操作的例子,读者可以...
《编程珠玑》第二版是计算机科学领域的一本经典著作,由Jon Bentley撰写,它以其深入浅出的方式探讨了程序设计中的诸多问题和解决方案。这本书不仅涵盖了算法和数据结构,还涉及了软件工程的实践与智慧,对于程序员...
《编程珠玑》一书将这些技巧和经验整理成章,涵盖了算法、数据结构、性能优化、代码质量等多个方面,是程序员自我提升的重要参考资料。书中强调的问题求解策略和程序设计思想,对于初学者和资深开发者都有很大的启发...
编程珠玑第二版及源代码实现(C/C++) 如果让程序员们列举他们喜欢的书籍,Jon Bentley的《编程珠玑》一定可以归于经典之列。如同精美的珍珠出自饱受沙砾折磨的牡蛎,程序员们的精彩设计也来源于曾经折磨他们的实际...
《编程珠玑》是计算机科学领域的一本经典著作,作者是Jon Bentley,它以其深入浅出的讲解方式,探讨了程序设计中的一些核心问题。这本书不仅涵盖了算法和数据结构,还涉及了问题解决、程序效率优化以及软件工程的...
《编程珠玑》是一本经典的计算机科学与编程书籍,作者是Jon Bentley。这本书以其独特的视角深入探讨了程序设计的艺术和技巧,旨在提升程序员的问题解决能力,优化算法,并提高代码效率。书中涵盖了一系列实用的编程...
每个`.cpp`文件都代表了《编程珠玑》中某一章节的C++代码实现,这为读者提供了一种实践和理解书中理论的途径。通过阅读和理解这些代码,读者不仅可以学习到编程技巧,还能体验到如何将理论知识应用到实际问题中,...
《编程珠玑》第一版是我早期职业生涯中阅读过的对我影响较大的书籍之一,在书中首次接触到的很多观点都让我长期受益。作者在这一版本中做了重要更新。新增加的很多例子让我耳目一新。 ——Steve McConnell,《代码...
编程珠玑 本书针对程序设计人员探讨了一系列的实际问题,这些问题... 本书在第一版的基础上增加了3个方面的新内容:测试、调试和计量,集合表示,字符串问题,并对第一版的所有程序都进行了改写,生成了等量的新代码。
《编程珠玑》是计算机科学领域的一本经典之作,作者是Jon Bentley,它以其独特的视角和深入浅出的讲解方式,向读者展示了编程艺术的精髓。这本书的第二版更是深受程序员和计算机科学家们的喜爱,因为它不仅涵盖了...
此外,还可以通过对比不同栏目的代码实现,来领悟各种编程思想和技巧,提高自己的编程素养。 总之,这个压缩包为读者提供了一个极好的机会,能够直接接触到《编程珠玑》中所讲述的编程实践,加深对书中理论的理解,...
"第二章questionC"提及的问题是关于"求变位词",这是一个常见的字符串处理问题,涉及到字符统计、排序以及字符串比较等基础知识。 变位词,又称为同字母异序词,是指两个或多个单词由完全相同的字母组成,但字母...
编程珠玑 java程序员应该读的书籍,好好的读了,很有帮助的了
源码通常会涵盖一些经典的算法实现,比如排序算法的C++或Java版本,让读者能够直观地看到算法在实际代码中的应用。 5. **性能优化**:《编程珠玑》特别关注程序性能的优化,涵盖了内存管理、I/O操作和算法效率等...
第一部分 编 程 技 术 第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中...
《编程珠玑》和其续篇是两部深受程序员喜爱的经典著作,主要涵盖了程序设计、算法分析和数据结构等核心编程领域。这两本书以其深入浅出的讲解方式和丰富的实例,帮助读者提升编程技巧和解决问题的能力。 在《编程...
《编程珠玑》是计算机科学领域的一本经典著作,作者是Jon Bentley,他在书中通过一系列有趣的问题和解决方案,深入浅出地探讨了程序设计的艺术和技巧。这本书的第二版中文PDF和源代码的提供,为中国的程序员和计算机...
根据提供的标题“编程珠玑(第二版)答案”和描述“编程珠玑(第二版)答案”,我们可以推测出这是关于《编程珠玑》这本书的相关解答资料。《编程珠玑》是一本经典的计算机科学书籍,作者为Jon Bentley。本书旨在...