《算法:第四版》练习1.1部分答案

以下答案纯属个人愚见,作为IT新手,算法代码中难免有逻辑漏洞和其他不足之处,欢迎朋友你点评拍砖,交流争辩能极大开阔思维,愿一起加油进步!^_^

1.1.19  在计算机上运行以下程序:

 1 public class Fibonacci {
 2
 3     public static long F(int N) {
 4         if(0 == N)
 5             return 0;
 6         if(1 == N)
 7             return 1;
 8         return F(N - 1) + F(N - 2);
 9     }
10
11     public static void main(String[] args) {
12         for(int N = 0; N < 100; ++N)
13             StdOut.println(N + "  " + F(N));
14     }
15
16 }

计算机用这段程序在一个小时之内能够得到F(N) 结果的最大N 值是多少?开发F(N) 的一 个更好的实现,用数组保存已经计算过的值。

 1 public class Fibonacci {
 2
 3     // Fibonacci数列计算,时间空间复杂度优化版
 4     private static int M = 100;
 5     private static long[] fib = new long[M];
 6     public static long fibonacciOptimization(int N) {
 7         if(0 == N)
 8             fib[0] = 0;
 9         else if(1 == N)
10             fib[1] = 1;
11         else
12             fib[N] = fib[N - 1] + fib[N -2];
13         return fib[N];
14     }
15
16     public static void main(String[] args) {
17         for(int N = 0; N < 100; ++N) {
18             fib[N] = fibonacciOptimization(N);
19             StdOut.println(N + "\t" + fib[N]);
20         }
21     }
22
23 }

1.1.20  编写一个递归的静态方法计算 ln( N! ) 的值。

 1     public static long factorial(int M) {
 2         if(0 == M || 1 == M)
 3             return 1;
 4         else
 5             return M * factorial(M - 1);
 6     }
 7
 8     public static double ln(int N) {
 9         return Math.log(factorial(N));
10     }
11
12     public static void main(String[] args) {
13         double val = ln(4);
14         StdOut.println(val);
15     }

1.1.21  编写一段程序,从标准输入按行读取数据,其中每行都包含一个名字和两个整数。然后用printf() 打印一张表格,每行的若干列数据包括名字、两个整数和第一个整数除以第二个整数的结果,精确到小数点后三位。可以用这种程序将棒球球手的击球命中率或者学生的考试分数制成表格。

 1     public static void main(String[] args) {
 2         int M = 3;
 3         int index = 0;
 4         String[] strs = new String[M];
 5         while(index < M)
 6             strs[index++] = StdIn.readLine();
 7         for(int i = 0; i < strs.length; ++i) {
 8             String[] arr = strs[i].split("\\s+");
 9             double temp = Double.parseDouble(arr[1]) / Double.parseDouble(arr[2]);
10             StdOut.printf("%-10s   %-10s   %-10s   %-13.3f\n", arr[0], arr[1], arr[2], temp);
11         };
12     }

1.1.22  使用1.1.6.4 节中的rank() 递归方法重新实现BinarySearch 并跟踪该方法的调用。每当该方法被调用时,打印出它的参数lo 和hi 并按照递归的深度缩进。提示:为递归方法添加一个参数来保存递归的深度。

 1     /**
 2      * 递归查找关键词的索引
 3      * @param key
 4      * @param arr
 5      * @param low
 6      * @param high
 7      * @return
 8      */
 9     public static int rank(int key, int[] arr, int low, int high, int depth) {
10         printCallInfo(low, high, depth);
11         if(low > high)
12             return -1;
13         int mid = low + ((high - low) >> 1);
14         if(key < arr[mid])
15             return rank(key, arr, low, mid - 1, depth + 1);
16         else if(key > arr[mid])
17             return rank(key, arr, mid + 1, high, depth + 1);
18         else
19             return mid;
20     }
21
22     /**
23      * 二分查找 : 递归描述
24      * @param key
25      * @param arr
26      * @return
27      */
28     public static int binarySearch(int key, int[] arr, int depth) {
29         return rank(key, arr, 0, arr.length - 1, depth);
30     }
31
32     /**
33      * 打印缩进
34      * @param indents    缩进数
35      */
36     private static void printIndent(final int indents) {
37         for(int i = 0; i < indents; ++i)
38             StdOut.print("----------");
39     }
40
41     /**
42      * 打印调用信息
43      * @param low
44      * @param high
45      * @param depth
46      */
47     private static void printCallInfo(int low, int high, int depth) {
48         StdOut.print(depth + "\t");
49         printIndent(depth);
50         StdOut.println(low + "\t" + high);
51     }
52
53     public static void main(String[] args) {
54         int N = 1024;
55         int[] arr = new int[N];
56         for(int i = 0; i < N; ++i)
57             arr[i] = StdRandom.uniform(N * 50);
58         // 排序
59         Arrays.sort(arr);
60         // 从随机数组中随机抽取一个元素作为关键字
61         // 输出随机数组
62         StdOut.print("seq = ");
63         for(int i = 0 ; i < N; ++i)
64             StdOut.print(arr[i] + "\t");
65         int key = arr[StdRandom.uniform(N)];
66         StdOut.println("\nkey = " + key);
67         StdOut.println("---------------------------------------------------------------------------------------");
68         binarySearch(key, arr, 0);
69     }

1.1.27  二项分布。估计用以下代码计算binomial(100, 50) 将会产生的递归调用次数:

1 public static double binomial(int N,int k, double p) {
2         if(N == 0 && k == 0)
3             return 1.0;
4         if(N < 0 || k < 0)
5             return 0.0;
6         return (1.0 - p) * binomial(N-1, k, p) + p * binomial(N-1, k-1, p);
7     }

将已经计算过的值保存在数组中并给出一个更好的实现。

 1     private static int binom_N = 100;
 2
 3     private static int binom_k = 50;
 4
 5     private static double[][] binom = new double[binom_N + 1][binom_k + 1];
 6
 7     private static double binomial(int N, int k, double p) {
 8         if(N < 0 || k < 0) {
 9             return 0.0;
10         } else if(N == 0 && k == 0) {
11             if(binom[N][k] == -1.0)
12                 binom[N][k] = 1.0;
13         } else {
14             if (binom[N][k] == -1.0)
15                 binom[N][k] = (1.0 - p) * binomial(N - 1, k, p) + p * binomial(N - 1, k - 1, p);
16         }
17         return binom[N][k];
18     }
19
20     public static void main(String[] args) {
21         // 数组binom初始化
22         for(int i = 0; i < binom_N + 1; ++i)
23             for(int j = 0; j < binom_k + 1; ++j)
24                 binom[i][j] = -1.0;
25         // 计算概率
26         double res = binomial(binom_N, binom_k, 0.25);
27         StdOut.println(res);
28     }

1.1.28  删除重复元素。修改BinarySearch 类中的测试用例来删去排序之后白名单中的所有重复元素。

1.1.29  等值键。为BinarySearch 类添加一个静态方法rank(),它接受一个键和一个整型有序数组(可能存在重复键)作为参数并返回数组中小于该键的元素数量,以及一个类似的方法count() 来返回数组中等于该键的元素的数量。注意:如果i 和j 分别是rank(key,a) 和count(key,a)的返回值,那么a[i..i+j-1] 就是数组中所有和key 相等的元素。看法:只有当key在数组中时才这样子。

 1 /**
 2  * 二分查找统计
 3  * @param key   待查找关键字
 4  * @param arr   待查找数组
 5  * @return  返回小于key的个数即比等于key的第一个元素的索引值,若找不到则返回-1
 6  */
 7 private static int countLowers(int key, int[] arr) {
 8     int low = 0;
 9     int high = arr.length - 1;
10     while(low <= high) {
11         int mid = low + ((high - low) >> 1);
12         if(key < arr[mid])
13             high = mid - 1;
14         else if(key > arr[mid])
15             low = mid + 1;
16         else {
17             while(mid > 0 && arr[mid] == arr[mid - 1])              // 注意判断条件的先后顺序
18                 -- mid;
19             return mid;
20         }
21     }
22     return low;     // -1; 根据算法原理可知low是小于key的个数
23 }
24
25 /**
26  * 统计与key相等的个数
27  * @param key   待查找关键字
28  * @param arr   待查找数组
29  * @return  返回与key相等的个数
30  */
31 private static int countEquals(int key, int[] arr) {
32     int lowers = countLowers(key, arr);
33     int idx = lowers;
34     if(idx == arr.length || key != arr[idx])                        // 注意判断条件的先后顺序
35         return 0;
36
37     int cnt = 1;
38     while((idx < arr.length - 1) && (arr[idx] == arr[idx + 1])) {   // 注意判断条件的先后顺序
39         ++ cnt;
40         ++ idx;
41     }
42     return cnt;
43 }
44
45 public static void main(String[] args) {
46     // 从文件读取数据
47     In in = new In("./data/tinyW.txt");
48     int[] whiteList = in.readAllInts();
49     // 排序并打印输出
50     Arrays.sort(whiteList);
51     for(int idx = 0; idx < whiteList.length; ++idx)
52         StdOut.print(whiteList[idx] + "\t");
53     StdOut.println();
54     // 从控制台读取关键字
55     int key = StdIn.readInt();
56     int lowers = countLowers(key, whiteList);
57     StdOut.println("小于\t" + key + "\t的个数是:\t" + lowers);
58     int equals = countEquals(key, whiteList);
59     StdOut.println("等于\t" + key + "\t的个数是:\t" + equals);
60 }

1.1.30  数组练习。编写一段程序,创建一个N×N 的布尔数组a[][]。其中当i 和j 互质时(没有相同因子),a[i][j] 为true,否则为false。

 1 /**
 2  * 判断两数是否互质,若两数的最大公约数是1则两数互质
 3  * @param a
 4  * @param b
 5  * @return  若互质则true,否则false
 6  */
 7 private static boolean isCoprime(int a, int b) {
 8     for(int i = 2; i < Math.sqrt(a); ++i) {
 9         if(a % i == 0 && b % i == 0)
10             return false;
11     }
12     return true;
13 }
14
15 /**
16  * 使用2300多年前的欧几里得算法求解两数的最大公约数
17  * @param p 数一
18  * @param q 数二
19  * @return  最大公约数
20  */
21 private static int gcd(int p, int q) {
22     if(q == 0)
23         return p;
24     int r = p % q;
25     return gcd(q, r);
26 }
27
28 private static boolean[][] boolArray(int N) {
29     // 创建NxN的布尔二维数组
30     boolean[][] boolArr = new boolean[N][N];
31     for(int i = 1; i <= N; ++i)
32         for(int j = 1; j <= N; ++j)
33             if(1 == gcd(i, j))
34                 boolArr[i - 1][j - 1] = true;
35             else
36                 boolArr[i - 1][j - 1] = false;
37     return boolArr;
38 }
39
40 public static void main(String[] args) {
41     int N = 5;
42     boolean[][] boolArr = boolArray(N);
43     for(int i = 0; i < N; ++i) {
44         for (int j = 0; j < N; ++j)
45             StdOut.print(boolArr[i][j] + "\t");
46         StdOut.println();
47     }
48 }

1.1.31  随机连接。编写一段程序,从命令行接受一个整数N 和double 值p(0 到1 之间)作为参数,在一个圆上画出大小为0.05 且间距相等的N 个点,然后将每对点按照概率p 用灰线连接。

 1 /**
 2  * 画圆
 3  * @param x 圆心x坐标
 4  * @param y 圆心y坐标
 5  * @param r 半径r
 6  */
 7 private static void drawCircle(double x, double y, double r) {
 8     StdDraw.setXscale(0, 2 * x);
 9     StdDraw.setYscale(0, 2 * y);
10     StdDraw.setPenRadius(0.003);
11     StdDraw.setPenColor(StdDraw.BOOK_LIGHT_BLUE);
12     StdDraw.circle(x, y, r);
13 }
14
15 /**
16  * 在圆上描点
17  * @param x0 圆心x坐标
18  * @param y0 圆心y坐标
19  * @param r 半径r
20  * @param N N个点
21  */
22 private static double[][] drawPoints(double x0, double y0, double r, int N) {
23     double[][] points = new double[N][2];
24     StdDraw.setPenRadius(0.005);
25     StdDraw.setPenColor(StdDraw.BOOK_RED);
26     for(int idx = 0; idx < N; ++idx) {
27         double x = x0 + r * Math.cos(2 * Math.PI * idx / N);
28         double y = y0 + r * Math.sin(2 * Math.PI * idx / N);
29         StdDraw.point(x, y);
30         points[idx][0] = x;
31         points[idx][1] = y;
32     }
33     return points;
34 }
35
36 /**
37  * 以概率p随机连接顶点集points中的点
38  * @param points    点集
39  * @param p 概率p
40  */
41 private static void randomLinkPoints(double[][] points, double p) {
42     StdDraw.setPenRadius(0.002);
43     StdDraw.setPenColor(StdDraw.LIGHT_GRAY);
44     int length = points.length;
45     for(int i = 0; i < length; ++i)
46         for(int j = 0; j < length; ++j)
47             if(true == StdRandom.bernoulli(p))
48                 StdDraw.line(points[i][0], points[i][1], points[j][0], points[j][1]); // 应该再建立一个包含x坐标和y坐标的数据结构
49 }
50
51 /**
52  * 在圆上画N个点然后每两点间以概率p连接
53  * @param N N个点
54  * @param p 概率p
55  */
56 private static void randomLink(int N, double p) {
57     double x = 10.0;
58     double y = 10.0;
59     double r = 9.0;
60     drawCircle(x, y, r);
61     double[][] points = drawPoints(x, y, r, N);
62     randomLinkPoints(points, p);
63 }
64
65 public static void main(String[] args) {
66     randomLink(20, 0.2);
67 }


^_^
时间: 2024-10-05 08:39:13

《算法:第四版》练习1.1部分答案的相关文章

算法第四版 在Eclipse中调用Algs4库

首先下载Eclipse,我选择的是Eclipse IDE for Java Developers64位版本,下载下来之后解压缩到喜欢的位置然后双击Eclipse.exe启动 然后开始新建项目,File -> New Java Project,项目名随便写,如下图 右键src文件夹,Add -> New Java Class,这里需要注意Name一栏里填写的内容就是类名,这里我写了TestAlgs4,为了测试「算法 第四版」作者给的那个测试样例 代码如下: import edu.princeto

算法(第四版)学习笔记之java实现选择排序

选择排序步骤: 1.找到数组中参与遍历比较的所有元素中的最小元素的下标: 2.将最小元素与数组中参与遍历比较的第一个元素进行交换(如果第一个元素就是最小元素的话,那么也会进行一次交换): 3.若数组中还有需要参与遍历比较的元素,则跳转到步骤1:否则排序结束. 在算法第四版中给出的所有排序均是适用于任意实现了Comparable接口的数据类型,若要将数字作为测试用例,请勿使用基本数据类型,改用Integer等实现了Comparable接口的对象. 选择排序代码如下: /** * * @author

算法第四版-文字版-下载地址-Robert Sedgewick

下载地址:https://download.csdn.net/download/moshenglv/10777447 算法第四版,文字版,可复制,方便copy代码 目录: 第1章 基 础 ....................... . ..........................11.1 基础编程模型 ..................................... 41.1.1 Java程序的基本结构 ................. 41.1.2原始数据类型与表达式

算法(第四版)之并查集(union-find算法)

开个新坑, 准备学习算法(第四版), 并把上面学到的东西写成博客, 毕竟以前也学过一点算法, 但效果甚微 并查集, 在这本书的第一章1.5中叫做union-find算法, 但在其他地方这个叫做并查集,就是说一系列点的连通问题,比如, 我们有十个点, 分别记作0~9: 加入我们要把2和4连接起来怎么表示呢? 首先我们会想到,给所有的点标上一个号, 来代表他们的连通关系, 我们初始化这个数就是他们id本身: 如果我们要连接2和4, 就使得4的id为2: 之后要连接间隔点任意两个点, 就把它们和它们相

C++ Primer 第四版中文完整版 和答案完整版

前段时间下载的C++Primer 第四版中文版 缺少第十到第十三章,终于下到了完整版的电子书还找到了完整的配套答案. 全部供大家免费下载: 下面是链接: 由于CSDN限制文件的大小所以C++primer 分了两个文件 还有答案是一个文件: http://download.csdn.net/my C++ Primer 第四版中文完整版 和答案完整版,布布扣,bubuko.com

算法第四版学习笔记之快速排序 QuickSort

软件:DrJava 参考书:算法(第四版) 章节:2.3快速排序(以下截图是算法配套视频所讲内容截图) 1:快速排序 2:

高等代数(第四版) 王萼芳课后答案

高等代数(第四版)课后习题答案 王萼芳.石生明编 高等教育出版社第1章 多次项 第2章 行列式高等代数 第3章 线性方程组 第4章 矩阵高等代数课后答案高等代数课后答案第5章 二次型第6章 线性空间 原文地址:https://www.cnblogs.com/suibian1/p/12534058.html

算法第四版学习——Coursera&amp;DrJava使用方法

引言 前段时间失业了,找工作的时候最深的两点体会是: 1.虽然做过大项目,做过很多复杂业务功能,涉及过很多知识领域.但是都很难表达清楚. 2.笔试遇到很多算法题,做得都比较头疼(糟糕),很多都直接影响了面试结果. 第一点我明白是需要不断总结和积累的,第二点勾起了我对算法学习的兴趣.大学学算法的时候,脱离实践,只谈时间.空间复杂度和实现难度,学完了就忘了,那样枯燥的算法我肯定不想再碰一遍. 偶然看到了Coursera的算法导论课程,遇到了大牛老师Robert Sedgewick,他的视频在网上下下

算法(第四版)学习笔记之java实现快速排序

快速排序是一种分治的排序算法.它将一个数组分成两个子数组,将两部分独立地排序.快速排序和归并排序是互补的,归并排序将两个子数组分别排序,并将有序的子数组归并以将整个数组排序:而快速排序则是当两个子数组有序时整个数组也就自然有序了.在快速排序中,切分的位置取决于数组的内容. 优点: 1.实现简单: 2.适用于各种不同的输入数据且在一般应用中比其他排序算法都要快得多: 3.原地排序: 4.时间复杂度为o(nlgn); 5.内循环比大多数排序算法都要短,比较次数少. 缺点:快速排序算法非常脆弱,在实现

算法(第四版)学习笔记之java实现堆排序

继上一篇实现基于堆的优先队列后,这次将利用上一次完成的基于堆的能够重复删除最大元素操作的优先队列来实现一种经典而优雅的排序算法,称之为堆排序. 堆排序可分为两个阶段: 1.构建堆:在堆的构建过程中,我们将原始数组重新组织安排进一个堆中: 2.下沉排序:从堆中按递减顺序取出所有元素并得到排序结果 具体的思想在下面的代码中有较为详细的注释: /** * * @author seabear * */ public class HeapSort { /** * 1.构造大根堆:与上一篇基于堆的优先队列相