习题解析第1章1. 解析:算法主要是指求解问题的方法。
计算机中的算法是求解问题的方法在计算机上的实现。
2. 解析:算法的五大特征是确定性、有穷性、输入、输出和可行性。
3. 解析:计算的算法,其中n是正整数。
可以取循环变量i的值从1开始,算i的平方,取平方值最接近且小于或者等于n的i即可。
4. 解析:可以使用反证法,设i=gcd(m, n)=gcd(n, m mod n),则设m=a*i,n=b*i,且a与b互质,这时m mod n=(a-x*b)*i,只需要证明b和a-x*b互质,假设二者不互质,可以推出a与b不互质,因此可以得到证明。
5. 解析:自然语言描述:十进制整数转换为二进制整数采用“除2取余,逆序排列”法。
具体做法是:用2整除十进制整数,可以得到一个商和余数;再用2去除商,又会得到一个商和余数,如此进行,直到商为0时为止,然后把先得到的余数作为二进制数的低位有效位,后得到的余数作为二进制数的高位有效位,依次排列起来。
流程图:如图*.1图*.1 十进制整数转换成二进制整数流程图6. 解析:a.如果线性表是数组,则可以进行随机查找。
由于有序,因此可以进行折半查找,这样可以在最少的比较次数下完成查找。
b.如果线性表是链表,虽然有序,则只能进行顺序查找,从链表头部开始进行比较,当发现当前节点的值大于待查找元素值,则查找失败。
7. 解析:本题主要是举例让大家了解算法的精确性。
过程中不能有含糊不清或者二义性的步骤。
大家根据可行的方式总结一下阅读一本书的过程即可。
8. 解析:数据结构中介绍的字典是一种抽象数据结构,由一组键值对组成,各个键值对的键各不相同,程序可以将新的键值对添加到字典中,或者基于键进行查找、更新或删除等操作。
由于本题已知元素唯一,因此大家可以据此建立一个自己的字典结构。
实现字典的方法有很多种:•最简单的就是使用链表或数组,但是这种方式只适用于元素个数不多的情况下;•要兼顾高效和简单性,可以使用哈希表;•如果追求更为稳定的性能特征,并且希望高效地实现排序操作的话,则可以使用更为复杂的平衡树。
在字典之上的主要操作可以有:创建操作,添加操作,删除操作,查找操作,以及必要的字典维护操作。
第2章1. 解析:根据本章所述,递归算法和非递归算法的数学分析方法分为5个步骤。
2. 解析:本题相当于对多项式找“主项”,也就是在除去常系数外,影响函数值递增速度最快的项。
a) 22310()n n n θ+∈b) 22(2)10n n n θ+∈ c) 121()c nθ+∈,c 为常数 d) 32log (log )n n θ∈e) 10log 3()nn θ∈3. 解析:本题中如果手套分左右手,则最优情况选2只,最差情况选12只。
本题中如果手套不分左右手,则最优情况仍然选2只,最差情况选4只。
从本题的初衷推测设置题目应该是分左右手的手套,在考虑颜色的情况下,选择一双进行匹配。
4. 解析:本题的一般解法可以使用高等数学中求二者比值的极限来确定结果。
a) 相同 b) 第一个小 c) 二者相同 d) 第一个大 e) 二者相同 f) 第一个小 5. 解析:6. 解析:参见本章例2.7。
第3章1. 解析:蛮力法主要依靠问题的定义,采用简单直接的求解方法。
由此决定了蛮力法是解决问题的最简单也是最普遍的算法,同时其经常作为简单问题求解的方法和衡量其他算法的依据。
2. 解析:2,6,1,4,5,3,2选择排序:|2 6 1 4 5 3 2i=0: min最后得2,交换二者。
1 |62 4 53 2 i=1: min最后得2,交换二者。
1 2 |6 4 5 3 2i=2: min最后得6,交换二者。
1 2 2 |4 5 3 6 i=3: min最后得5,交换二者。
1 2 2 3 |5 4 6 i=4: min最后得5,交换二者1 2 2 3 4 |56i=5: min最后得5。
1 2 2 3 4 5 |6结束。
冒泡排序:2 6 1 4 53 22 1 4 53 2 |6 i=0: 最大值6就位。
1 2 4 3 2 |5 6 i=1:第二大值5就位。
1 2 3 2 |4 5 6 i=2:第三大值4就位。
1 2 2 |3 4 5 6 i=3:第四大值3就位。
1 2 |2 3 4 5 6 i=4:第五大值2就位。
1 |2 23456 i=5:第六大值2就位,剩余的1也就位,排序结束。
3. 解析:选择排序不稳定,如3.1.1节例子:4,4,2。
冒泡排序稳定。
4. 解析:如2题例子,到i=4时就没有发生交换的活动了。
这时可以在冒泡排序的交换部分加入一个布尔变量,如本次循环中没有发生交换,则以后的扫描就可以不进行。
5. 解析:如果n个点共线,则其最近对只需要考察相邻的点对,因此在对点进行按行坐标排序后,只需要两两计算相邻两点距离,就可以找到最近对。
6. 解析:所有的过程与寻找二维空间中的最近点对类似,只是计算距离的公式变为:sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)+(p1.z-p2.z)*(p1.z-p2.z) 使用循环计算任意两个点之间的距离,然后记录最小值即可。
类似的,如果推广到n维空间,需要考虑空间中任意两点的距离计算公式,同样计算每两个点之间的距离,并记录最小距离即可。
7. 解析:a) 线段的凸包为本身,极点为两个端点。
b) 正方形的凸包为本身,极点为四个顶点。
c) 正方形的边界不是凸包,凸包为正方形(包括边界和部)。
d) 直线的凸包为本身,没有极点。
8. 解析:哈密顿回路的穷举查找算法,首选选择起点(图中任意一个点开始),之后不断寻找下一个点,下一个点应该满足:1) 不在已经走过的点中;2)与上一个点有直连路径。
如果这样能找到回到起点的路径,并且遍历所有点,则为一条哈密顿回路。
然后依次进行下一个可行点的选择。
9. 解析:生成给定元素的一个排列,通过连续比较它们之间的元素,检查它们是否符合排序的要求。
如果符合就停止,否则重新生成新的排列。
最差情况生成排列的个数是!n,每趟连续元素比较次数为n-1次。
所以效率类型为O n n 。
(!*(1))第4章1. 解析:假定把16枚硬币上网例子看作一个大的问题。
(1)把这一问题分成两个小问题,随机选择8个硬币作为第一组称为A组,剩下的8个硬币作为第二组称为B组;这样,就把16个硬币的问题分成两个8个银币的问题来解决;(2)判断A组和B组中是否有伪币,可以使用仪器比较A组硬币和B组硬币的重量;假如两组硬币重量相等,则可以判断伪币不存在;假如两组硬币重量不相等,则存在伪币,并且可以判断它位于较轻的那一组硬币中;(3)假设B是轻的那一组,因此再把它分成两组,每组有4个硬币,称其中一组为B1,另一组为B2,比较这两组,肯定有一组轻一些,假设B1轻,则伪币在B1中,再将B1分为两组,每组有两个硬币,称其中一组为B1a,另一组为B1b。
比较这两组,可以得到一个较轻的组,由于这个组织有两个硬币,因此不必再细分。
比较组中两个硬币的重量,可以立即知道哪个硬币轻一些,轻币就是要找的伪币;最终,比较次数为4次。
2. 解析:逆序对是指在序列{a0,a1,a2...a n}中,若a i<a j(i>j),则(a i,a j)上一对逆序对。
而逆序数是指序列中逆序对的个数。
例如:1 2 3是顺序,则逆序数是0;1 3 2中(2,3)满足逆序对的条件,所以逆序数只有1;3 2 1中(1,2)(1,3)(2,3)满足逆序对,所以逆序是3。
由定义不能想象,序列n的逆序数围在[0,n*(n-1)/2],其中顺序时逆序数为0,完全逆序时逆序数是n*(n-1)/2。
对于一个数组s将其分为2个部分s1和s2,求s1和s2的逆序对个数,再求s1和s2合并后逆序对的个数:这个过程与merge排序的过程是一样的,可以使用merge排序求得。
代码如下://a为字符数组,len为字符数组的长度int number = 0; //number表示逆序对的个数void copy(char *dest, char *src, int l, int r){while(l <= r){dest[l] = src[l]; l++;}void mergeSort(char *a, int size){char *b = (char*)malloc(sizeof(char) * size);mergePass(a, b, 0, size - 1);free(b);}void mergePass(char *a, char *b, int l, int r) {int m;if(l < r){m = (l + r) / 2;mergePass(a,b,l,m);mergePass(a,b,m+1,r);merge(a,b,l,m,r);copy(a,b,l,r);}}void merge(char *a, char *b, int l, int m, int r) {int i = l, j = m + 1;while( i <= m && j <= r){if(a[i] <= a[j]) b[l++] = a[i++];else{b[l++] = a[j++];number += m-i+1;}while(i <= m) b[l++] = a[i++];while(j <= r) b[l++] = a[j++];}3. 解析:当序列A[1..n]中的元素的个数n=2时,通过直接比较即可找出序列的第2大元素。
当n>2时,先求出序列A[1..n-1]中的第1大元素x1和第2大元素x2;然后,通过2次比较即可在三个元素x1,x2和A[n]中找出第2大元素,该元素即为A[1..n]中的第2大元素。
SecondElement (A[low..high], max1, max2){ //假设主程序中调用该过程条件为high-low>=2if(high-low==2){ if(A[low]<A[high]) { max2=A[low]; max1=A[high]; }else { max2=A[high]; max1=A[low]; }}else{ SecondElement (A[low .. high],x1,x2);if(x1<=A[n]) {max2=max1; max1=A[n];}elseif(x2>=A[n]) {max2=x2; max1=x1;}else {max2=A[n]; max1=x1;}}}该算法的时间复杂度满足如下递归方程:T(n)=T(n-1)+2; T(2)=1。