算法复习课后习题部分
- 格式:doc
- 大小:1.31 MB
- 文档页数:19
算法设计与分析第二版课后习题解答算法设计与分析基础课后练习答案习题 4.设计一个计算的算法,n是任意正整数。
除了赋值和比较运算,该算法只能用到基本的四则运算操作。
算法求//输入:一个正整数n2//输出:。
step1:a=1;step2:若a*a 5. a.用欧几里德算法求gcd。
b. 用欧几里德算法求gcd,比检查min{m,n}和gcd间连续整数的算法快多少倍?请估算一下。
a. gcd(31415, 14142) = gcd(14142, 3131) = gcd(3131, 1618) =gcd(1618, 1513) = gcd(1513,105) = gcd(1513, 105) = gcd(105, 43) =gcd(43, 19) = gcd(19, 5) = gcd(5, 4) = gcd(4, 1) = gcd(1, 0) = 1.b.有a可知计算gcd欧几里德算法做了11次除法。
连续整数检测算法在14142每次迭代过程中或者做了一次除法,或者两次除法,因此这个算法做除法的次数鉴于1·14142 和 2·14142之间,所以欧几里德算法比此算法快1·14142/11 ≈ 1300 与 2·14142/11 ≈ 2600 倍之间。
6.证明等式gcd(m,n)=gcd(n,m mod n)对每一对正整数m,n都成立. Hint:根据除法的定义不难证明:如果d整除u和v, 那么d一定能整除u±v;如果d整除u,那么d也能够整除u的任何整数倍ku.对于任意一对正整数m,n,若d能整除m和n,那么d一定能整除n和r=m mod n=m-qn;显然,若d能整除n和r,也一定能整除m=r+qn和n。
数对(m,n)和(n,r)具有相同的公约数的有限非空集,其中也包括了最大公约数。
故gcd(m,n)=gcd(n,r)7.对于第一个数小于第二个数的一对数字,欧几里得算法将会如何处理?该算法在处理这种输入的过程中,上述情况最多会发生几次? Hint:对于任何形如0 gcd(m,n)=gcd(n,m)并且这种交换处理只发生一次.对于所有1≤m,n≤10的输入, Euclid算法最少要做几次除法?(1次) b. 对于所有1≤m,n≤10的输入, Euclid算法最多要做几次除法?(5次) gcd(5,8) 习题 1.(农夫过河)P—农夫 W—狼G—山羊C—白菜 2.(过桥问题)1,2,5,10---分别代表4个人, f—手电筒4. 对于任意实系数a,b,c, 某个算法能求方程ax^2+bx+c=0的实根,写出上述算法的伪代码(可以假设sqrt(x)是求平方根的函数) 算法Quadratic(a,b,c)//求方程ax^2+bx+c=0的实根的算法 //输入:实系数a,b,c//输出:实根或者无解信息 If a≠0D←b*b-4*a*c If D>0temp←2*ax1←(-b+sqrt(D))/temp x2←(-b-sqrt(D))/temp return x1,x2else if D=0 return –b/(2*a) else return “no real roots” else //a=0if b≠0 return –c/b else //a=b=0if c=0 return “no real numbers”else return “no real roots”5. 描述将十进制整数表达为二进制整数的标准算法 a.用文字描述 b.用伪代码描述解答:a.将十进制整数转换为二进制整数的算法输入:一个正整数n输出:正整数n相应的二进制数第一步:用n除以2,余数赋给Ki(i=0,1,2...),商赋给n 第二步:如果n=0,则到第三步,否则重复第一步第三步:将Ki按照i从高到低的顺序输出 b.伪代码算法 DectoBin(n)//将十进制整数n转换为二进制整数的算法 //输入:正整数n//输出:该正整数相应的二进制数,该数存放于数组Bin[1...n]中 i=1while n!=0 do { Bin[i]=n%2; n=(int)n/2; i++; } while i!=0 do{ print Bin[i]; i--; }9.考虑下面这个算法,它求的是数组中大小相差最小的两个元素的差.(算法略) 对这个算法做尽可能多的改进. 算法 MinDistance(A[0..n-1]) //输入:数组A[0..n-1] //输出:the smallest distance d between two of its elements习题1. 考虑这样一个排序算法,该算法对于待排序的数组中的每一个元素,计算比它小的元素个数,然后利用这个信息,将各个元素放到有序数组的相应位置上去.a.应用该算法对列表”60,35,81,98,14,47”排序b.该算法稳定吗?c.该算法在位吗? 解:a. 该算法对列表”60,35,81,98,14,47”排序的过程如下所示:b.该算法不稳定.比如对列表”2,2*”排序c.该算法不在位.额外空间for S and Count 4.(古老的七桥问题) 第2章习题7.对下列断言进行证明:(如果是错误的,请举例) a. 如果t(n)∈O(g(n),则g(n)∈Ω(t(n)) b.α>0时,Θ(αg(n))= Θ(g(n)) 解:a. 这个断言是正确的。
2.3 课后习题解答2.3.2 判断题1.线性表的逻辑顺序与存储顺序总是一致的。
〔×〕2.顺序存储的线性表可以按序号随机存取。
〔√〕3.顺序表的插入和删除操作不需要付出很大的时间代价,因为每次操作平均只有近一半的元素需要移动。
〔×〕4.线性表中的元素可以是各种各样的,但同一线性表中的数据元素具有一样的特性,因此属于同一数据对象。
〔√〕5.在线性表的顺序存储构造中,逻辑上相邻的两个元素在物理位置上并不一定相邻。
〔×〕6.在线性表的链式存储构造中,逻辑上相邻的元素在物理位置上不一定相邻。
〔√〕7.线性表的链式存储构造优于顺序存储构造。
〔×〕8.在线性表的顺序存储构造中,插入和删除时移动元素的个数与该元素的位置有关。
〔√〕9.线性表的链式存储构造是用一组任意的存储单元来存储线性表中数据元素的。
〔√〕10.在单链表中,要取得某个元素,只要知道该元素的指针即可,因此,单链表是随机存取的存储构造。
〔×〕11.静态链表既有顺序存储的优点,又有动态链表的优点。
所以它存取表中第i 个元素的时间与i 无关。
〔×〕12.线性表的特点是每个元素都有一个前驱和一个后继。
〔×〕2.3.3 算法设计题1.设线性表存放在向量A[arrsize] 的前 elenum 个分量中,且递增有序。
试写一算法,将x 插入到线性表的适当位置上,以保持线性表的有序性,并且分析算法的时间复杂度。
【提示】直接用题目中所给定的数据构造〔顺序存储的思想是用物理上的相邻表示逻辑上的相邻,不一定将向量和表示线性表长度的变量封装成一个构造体〕,因为是顺序存储,分配的存储空间是固定大小的,所以首先确定是否还有存储空间,假设有,那么根据原线性表中元素的有序性,来确定插入元素的插入位置,后面的元素为它让出位置,〔也可以从高低标端开始一边比拟,一边移位〕然后插入x ,最后修改表示表长的变量。
int insert (datatype A[],int *elenum,datatype x)/* 设 elenum 为表的最大下标*/ {if (*elenum==arrsize-1)return 0;/* 表已满,无法插入*/else {i=*elenum;while (i>=0 && A[i]>x)/* 边找位置边移动*/{A[i+1]=A[i];i--;}/* 插入成功 */A[i+1]=x;(*elenum)++;return 1;}}时间复杂度为O(n) 。
习题13.设计算法求数组中相差最小的两个元素(称为最接近数)的差。
要求分别给出伪代码和C++描述。
//采用分治法//对数组先进行快速排序//在依次比较相邻的差#include <iostream>using namespace std;int partions(int b[],int low,int high){int prvotkey=b[low];b[0]=b[low];while (low<high){while (low<high&&b[high]>=prvotkey)--high;b[low]=b[high];while (low<high&&b[low]<=prvotkey)++low;b[high]=b[low];}b[low]=b[0];return low;}void qsort(int l[],int low,int high){int prvotloc;if(low<high){prvotloc=partions(l,low,high); //将第一次排序的结果作为枢轴qsort(l,low,prvotloc-1); //递归调用排序由low 到prvotloc-1qsort(l,prvotloc+1,high); //递归调用排序由 prvotloc+1到 high}}void quicksort(int l[],int n){qsort(l,1,n); //第一个作为枢轴,从第一个排到第n个}int main(){int a[11]={0,2,32,43,23,45,36,57,14,27,39};int value=0;//将最小差的值赋值给valuefor (int b=1;b<11;b++)cout<<a[b]<<' ';cout<<endl;quicksort(a,11);for(int i=0;i!=9;++i){if( (a[i+1]-a[i])<=(a[i+2]-a[i+1]) )value=a[i+1]-a[i];elsevalue=a[i+2]-a[i+1];}cout<<value<<endl;return 0;}4.设数组a[n]中的元素均不相等,设计算法找出a[n]中一个既不是最大也不是最小的元素,并说明最坏情况下的比较次数。
Program算法设计与分析基础中文版答案习题5..证明等式gcd(m,n)=gcd(n,m mod n)对每一对正整数m,n都成立.Hint:根据除法的定义不难证明:如果d整除u和v, 那么d一定能整除u±v;如果d整除u,那么d也能够整除u的任何整数倍ku.对于任意一对正整数m,n,若d能整除m和n,那么d一定能整除n和r=m mod n=m-qn;显然,若d能整除n和r,也一定能整除m=r+qn和n。
数对(m,n)和(n,r)具有相同的公约数的有限非空集,其中也包括了最大公约数。
故gcd(m,n)=gcd(n,r)6.对于第一个数小于第二个数的一对数字,欧几里得算法将会如何处理?该算法在处理这种输入的过程中,上述情况最多会发生几次?Hint:对于任何形如0<=m<n的一对数字,Euclid算法在第一次叠代时交换m和n, 即gcd(m,n)=gcd(n,m)并且这种交换处理只发生一次..对于所有1≤m,n≤10的输入, Euclid算法最少要做几次除法?(1次)b. 对于所有1≤m,n≤10的输入, Euclid算法最多要做几次除法?(5次)gcd(5,8)习题1.(农夫过河)P—农夫 W—狼 G—山羊 C—白菜2.(过桥问题)1,2,5,10---分别代表4个人, f—手电筒4. 对于任意实系数a,b,c, 某个算法能求方程ax^2+bx+c=0的实根,写出上述算法的伪代码(可以假设sqrt(x)是求平方根的函数)算法Quadratic(a,b,c)描述将十进制整数表达为二进制整数的标准算法a.用文字描述b.用伪代码描述解答:a.将十进制整数转换为二进制整数的算法输入:一个正整数n输出:正整数n相应的二进制数第一步:用n除以2,余数赋给Ki(i=0,1,2...),商赋给n第二步:如果n=0,则到第三步,否则重复第一步第三步:将Ki按照i从高到低的顺序输出b.伪代码算法 DectoBin(n).n]中i=1while n!=0 do {Bin[i]=n%2;n=(int)n/2;i++;}while i!=0 do{print Bin[i];i--;}9.考虑下面这个算法,它求的是数组中大小相差最小的两个元素的差.(算法略)对这个算法做尽可能多的改进.算法 MinDistance(A[0..n-1])n-1]a.应用该算法对列表”60,35,81,98,14,47”排序b.该算法稳定吗?c.该算法在位吗?解:a. 该算法对列表”60,35,81,98,14,47”排序的过程如下所示:b.该算法不稳定.比如对列表”2,2*”排序c.该算法不在位.额外空间for S and Count[]4.(古老的七桥问题)习题1.请分别描述一下应该如何实现下列对数组的操作,使得操作时间不依赖数组的长度.a.删除数组的第i个元素(1<=i<=n)b.删除有序数组的第i个元素(依然有序)hints:a. Replace the i th element with the last element and decrease the array size of 1b. Replace the ith element with a special symbol that cannot be a value of the array’s element., 0 for an array of positive numbers ) to mark the i th position is empty. (“lazy deletion”)第2章习题7.对下列断言进行证明:(如果是错误的,请举例)a. 如果t(n)∈O(g(n),则g(n)∈Ω(t(n))b.α>0时,Θ(αg(n))= Θ(g(n))解:a. 这个断言是正确的。
算法设计与分析第三版第四章课后习题答案4.1 线性时间选择问题习题4.1问题描述:给定一个长度为n的无序数组A和一个整数k,设计一个算法,找出数组A中第k小的元素。
算法思路:本题可以使用快速选择算法来解决。
快速选择算法是基于快速排序算法的思想,通过递归地划分数组来找到第k小的元素。
具体步骤如下: 1. 选择数组A的一个随机元素x作为枢纽元。
2. 使用x将数组划分为两个子数组A1和A2,其中A1中的元素小于等于x,A2中的元素大于x。
3. 如果k等于A1的长度,那么x就是第k小的元素,返回x。
4. 如果k小于A1的长度,那么第k小的元素在A1中,递归地在A1中寻找第k小的元素。
5. 如果k大于A1的长度,那么第k小的元素在A2中,递归地在A2中寻找第k-A1的长度小的元素。
6. 递归地重复上述步骤,直到找到第k小的元素。
算法实现:public class LinearTimeSelection {public static int select(int[] A, int k) { return selectHelper(A, 0, A.length - 1, k);}private static int selectHelper(int[] A, int left, int right, int k) {if (left == right) {return A[left];}int pivotIndex = partition(A, left, righ t);int length = pivotIndex - left + 1;if (k == length) {return A[pivotIndex];} else if (k < length) {return selectHelper(A, left, pivotInd ex - 1, k);} else {return selectHelper(A, pivotIndex + 1, right, k - length);}}private static int partition(int[] A, int lef t, int right) {int pivotIndex = left + (right - left) / 2;int pivotValue = A[pivotIndex];int i = left;int j = right;while (i <= j) {while (A[i] < pivotValue) {i++;}while (A[j] > pivotValue) {j--;}if (i <= j) {swap(A, i, j);i++;j--;}}return i - 1;}private static void swap(int[] A, int i, int j) {int temp = A[i];A[i] = A[j];A[j] = temp;}}算法分析:快速选择算法的平均复杂度为O(n),最坏情况下的复杂度为O(n^2)。
第一章1. 算法分析题算法分析题1-1 求下列函数的渐进表达式(1). 3n^2 + 10n < 3n^2 + 10n^2 = 13n^2 = O(n^2)(2). n^2 / 10 + 2^n当n>5是,n^2 〈2 ^n所以,当n >= 1时,n^2/10 〈2 ^n故:n^2/10 + 2^n < 2 ^n + 2^n = 2*2^n = O(2^n)(3). 21 + 1/n < 21 + 1 = 22 = O(1)(4). log(n^3)=3log(n)=O(log(n))(5). 10log(3^n)= (10log3)n = O(n)算法分析题1—6(1)因为:f(n)=log(n^2) = 2log(n); g(n) = log(n) + 5所以:f(n)=Θ(log(n)+5)=Θ(g(n))(2)因为:log(n) 〈√n ; f(n)= 2log(n);g(n)=√n所以:f(n)= O(g(n))(3)因为:log(n)< n;f(n) = n;g(n) = log(n^2) = 2log(n)所以;f(n)= Ω(g(n))(4)因为:f(n) = nlogn +n; g(n) = logn所以:f(n) =Ω(g(n))(5)因为: f(n)= 10;g(n) = log(10)所以:f(n)=Θ(g(n))(6)因为: f(n)=log^2(n);g(n)= log(n)所以:f(n) ==Ω(g(n))(7)因为: f(n) = 2^n < 100*2^n; g(n)=100n^2; 2^n > n ^2所以:f(n)= Ω(g(n))(8)因为:f(n)= 2^n; g(n)= 3 ^n;2 ^n 〈3 ^n所以:f(n)= O(g(n))习题1-9 证明:如果一个算法在平均情况下的计算时间复杂性为Θ(f(n)),该算法在最坏情况下所需的计算时间为Ω(f(n)).分析与解答:因此,Tmax(N) = Ω(Tavg(N)) = Ω(Θ(f(n)))=Ω(f(n))。
数据结构与算法python语⾔实现第4章课后习题R-4.1 对于⼀个含有n个元素的序列S,描述⼀个递归算法查找其最⼤值。
所给出的递归算法时间复杂度和空间复杂度各是多少? python中三⽬运算符的写法x if(x>y)) else ydef max(data,n):if n==1:return data[0]else:m=max(data,n-1)return data[n-1] if(data[n-1]>m) else m共执⾏n次递归调⽤,因为它花费恒定的时间执⾏⾮递归的部分 所以时间复杂度是O(n)空间复杂度也是O(n)R-4.2使⽤在代码段4-11中实现的传统函数,绘制出power(2,5)函数计算的递归跟踪R-4.3如代码段4-12中实现的函数所⽰,使⽤重复平⽅算法,绘制出power(2,18)函数计算的递归跟踪R-4.4 绘制函数reverse(S,0,5)(代码段4-10)执⾏的递归追踪,其中S=[4,3,6,2,6]R-4.6 写⼀个递归函数,⽤于计算第n个调和数,其中 Hn=1+1/2+1/3+…+1/ndef harmonic(n):if n==1:return 1else:return harmonic(n-1)+1/nprint(harmonic(6))R-4.7 写⼀个递归函数,它可以把⼀串数字转换成对应的整数def tonum(data,m,n):if m==len(data)-1:return data[m]else:return data[m]*pow(10,n-1)+tonum(data,m+1,n-1)data=[1,2,3,4,5]print(tonum(data,0,len(data)))R-4.8Isabel⽤⼀种有趣的⽅法来计算⼀个含有n个整数的序列A的所有元素之和,其中n是2的幂.她创建⼀个新的序列B,其⼤⼩是序列A的⼀半并且设置B[i]=A[2i]+A[2i+1] (i=0,1,…,(n/2)-1)。
算法设计与分析第二版课后习题及解答算法设计与分析基础课后练习答案习题1.14.设计一个计算的算法,n是任意正整数。
除了赋值和比较运算,该算法只能用到基本的四则运算操作。
算法求 //输入:一个正整数n2//输出:。
step1:a1; step2:若a*an 转step 3,否则输出a; step3:aa+1转step 2;5. a.用欧几里德算法求gcd(31415,14142)。
b. 用欧几里德算法求gcd(31415,14142),比检查min{m,n}和gcd(m,n)间连续整数的算法快多少倍?请估算一下。
a. gcd31415, 14142 gcd14142, 3131 gcd3131, 1618 gcd1618, 1513 gcd1513, 105 gcd1513, 105 gcd105, 43 gcd43, 19 gcd19, 5 gcd5, 4 gcd4, 1 gcd1, 0 1.b.有a可知计算gcd(31415,14142)欧几里德算法做了11次除法。
连续整数检测算法在14142每次迭代过程中或者做了一次除法,或者两次除法,因此这个算法做除法的次数鉴于1?14142 和 2?14142之间,所以欧几里德算法比此算法快1?14142/11 ≈1300 与2?14142/11 ≈ 2600 倍之间。
6.证明等式gcdm,ngcdn,m mod n对每一对正整数m,n都成立.Hint:根据除法的定义不难证明:如果d整除u和v, 那么d一定能整除u±v;如果d整除u,那么d也能够整除u的任何整数倍ku.对于任意一对正整数m,n,若d能整除m和n,那么d一定能整除n和rm mod nm-qn;显然,若d能整除n和r,也一定能整除mr+qn和n。
数对m,n和n,r具有相同的公约数的有限非空集,其中也包括了最大公约数。
故gcdm,ngcdn,r7.对于第一个数小于第二个数的一对数字,欧几里得算法将会如何处理?该算法在处理这种输入的过程中,上述情况最多会发生几次?Hint:对于任何形如0mn的一对数字,Euclid算法在第一次叠代时交换m和n, 即gcdm,ngcdn,m并且这种交换处理只发生一次.8.a.对于所有1≤m,n≤10的输入, Euclid算法最少要做几次除法?1次b. 对于所有1≤m,n≤10的输入, Euclid算法最多要做几次除法?5次gcd5,8习题1.21.农夫过河P?农夫W?狼 G?山羊 C?白菜2.过桥问题1,2,5,10---分别代表4个人, f?手电筒4. 对于任意实系数a,b,c, 某个算法能求方程ax^2+bx+c0的实根,写出上述算法的伪代码可以假设sqrtx是求平方根的函数算法Quadratica,b,c//求方程ax^2+bx+c0的实根的算法//输入:实系数a,b,c//输出:实根或者无解信息If a≠0D←b*b-4*a*cIf D0temp←2*ax1←-b+sqrtD/tempx2←-b-sqrtD/tempreturn x1,x2else if D0 return ?b/2*ael se return “no real roots”else //a0if b≠0 return ?c/belse //ab0if c0 return “no real numbers”else return “no real roots”5. 描述将十进制整数表达为二进制整数的标准算法a.用文字描述b.用伪代码描述解答:a.将十进制整数转换为二进制整数的算法输入:一个正整数n输出:正整数n相应的二进制数第一步:用n除以2,余数赋给Kii0,1,2,商赋给n第二步:如果n0,则到第三步,否则重复第一步第三步:将Ki按照i从高到低的顺序输出b.伪代码算法 DectoBinn//将十进制整数n转换为二进制整数的算法//输入:正整数n//输出:该正整数相应的二进制数,该数存放于数组Bin[1n]中i1while n!0 doBin[i]n%2;nintn/2;i++;while i!0 doprint Bin[i];i--;9.考虑下面这个算法,它求的是数组中大小相差最小的两个元素的差.算法略对这个算法做尽可能多的改进.算法 MinDistanceA[0..n-1]//输入:数组A[0..n-1]//输出:the smallest distance d between two of its elements 习题1.3考虑这样一个排序算法,该算法对于待排序的数组中的每一个元素,计算比它小的元素个数,然后利用这个信息,将各个元素放到有序数组的相应位置上去.a.应用该算法对列表”60,35,81,98,14,47”排序b.该算法稳定吗?c.该算法在位吗?解:a. 该算法对列表”60,35,81,98,14,47”排序的过程如下所示:b.该算法不稳定.比如对列表”2,2*”排序c.该算法不在位.额外空间for S and Count[]4.古老的七桥问题第2章习题2.17.对下列断言进行证明:如果是错误的,请举例a. 如果tn∈Ogn,则gn∈Ωtnb.α0时,Θαgn Θgn解:a这个断言是正确的。
算法与数据结构C语⾔版课后习题答案(机械⼯业出版社)第3,4章习题参考答案第3章栈和队列⼀、基础知识题3.1有五个数依次进栈:1,2,3,4,5。
在各种出栈的序列中,以3,4先出的序列有哪⼏个。
(3在4之前出栈)。
【解答】34215 ,34251,345213.2铁路进⾏列车调度时,常把站台设计成栈式结构,若进站的六辆列车顺序为:1,2,3,4,5,6,那么是否能够得到435612, 325641, 154623和135426的出站序列,如果不能,说明为什么不能;如果能,说明如何得到(即写出"进栈"或"出栈"的序列)。
【解答】输⼊序列为123456,不能得出435612和154623。
不能得到435612的理由是,输出序列最后两元素是12,前⾯4个元素(4356)得到后,栈中元素剩12,且2在栈顶,不可能让栈底元素1在栈顶元素2之前出栈。
不能得到154623的理由类似,当栈中元素只剩23,且3在栈顶,2不可能先于3出栈。
得到325641的过程如下:1 2 3顺序⼊栈,32出栈,得到部分输出序列32;然后45⼊栈,5出栈,部分输出序列变为325;接着6⼊栈并退栈,部分输出序列变为3256;最后41退栈,得最终结果325641。
得到135426的过程如下:1⼊栈并出栈,得到部分输出序列1;然后2和3⼊栈,3出栈,部分输出序列变为13;接着4和5⼊栈,5,4和2依次出栈,部分输出序列变为13542;最后6⼊栈并退栈,得最终结果135426。
3.3若⽤⼀个⼤⼩为6的数组来实现循环队列,且当前rear和front的值分别为0和3,当从队列中删除⼀个元素,再加⼊两个元素后,rear和front的值分别为多少?【解答】2和43.4设栈S和队列Q的初始状态为空,元素e1,e2,e3,e4,e5和e6依次通过栈S,⼀个元素出栈后即进队列Q,若6个元素出队的序列是e3,e5,e4,e6,e2,e1,则栈S的容量⾄少应该是多少?【解答】43.5循环队列的优点是什么,如何判断“空”和“满”。
第一章3. 最大公约数为1。
快1414倍。
程序1-2的while 循环体做了10次,程序1-3的while 循环体做了14141次(14142-2循环)8.(1)画线语句的执行次数为log n ⎡⎤⎢⎥。
(log )n O 。
(2)画线语句的执行次数为111(1)(21)16jnii j k n n n ===++=∑∑∑。
3()n O 。
(3)画线语句的执行次数为。
O 。
(4)当n 为奇数时画线语句的执行次数为(1)(1)4n n +-, 当n 为偶数时画线语句的执行次数为 (2)4n n +。
2()n O 。
10.(1) 当 1n ≥ 时,225825n n n -+≤,所以,可选 5c =,01n =。
对于0n n ≥,22()5825f n n n n =-+≤,所以,22582()-+=O n n n 。
(2) 当 8n ≥ 时,2222582524n n n n n -+≥-+≥,所以,可选 4c =,08n =。
对于0n n ≥,22()5824f n n n n =-+≥,所以,22582()-+=Ωn n n 。
(3) 由(1)、(2)可知,取14c =,25c =,08n =,当0n n ≥时,有22212582c n n n c n ≤-+≤,所以22582()-+=Θn n n 。
11. (1) 当3n ≥时,3log log n n n <<,所以()20log 21f n n n n =+<,3()log 2g n n n n =+>。
可选212c =,03n =。
对于0n n ≥,()()f n cg n ≤,即()(())f n g n =O 。
(2) 当 4n ≥ 时,2log log n n n <<,所以 22()/log f n n n n =<,22()log g n n n n =≥。
可选 1c =,04n =。
树的按层次遍历:template<class T, class Func> //void LevelOrder(treenode<T> *x, Func Visit){ queue<treenode<T> *> Q;Q.push(x);while(!Q.empty()){ x = Q.front(), Q.pop();if(x == 0) continue;Visit(x); // visit x// put x's children on queueQ.push(x->first);for(x = x->first; x != 0; x = x->next) Q.push(x->next);}}图的宽度优先遍历连通图的宽度优先搜索(BFS):// BFS.h#pragma once#include <queue>#include "Matrix.h" // 用于邻接矩阵void BFS(const Matrix <bool> &G, int v, vector <int> &Visited) { // G为图的邻接矩阵,从顶点v开始,已访问的顶点标记为// Visited[i]=访问序号,Visited各分量已经初始化为0。
int n = G.Rows(), k, w; // k为访问序号,v、w为顶点序号。
queue <int> Q;Visited[v] = k = 1, Q.push(v); // 访问v,v加入队列Qwhile(!Q.empty()){ v = Q.front(), Q.pop(); // 取出队首元素vfor(w = 0; w < n; ++w)if(!Visited[w] && G[v][w] == 1)++k, Visited[w] = k, Q.push(w);}}一般图的宽度优先遍历(BFT):#include "Algorithm.hpp" // 用于邻接矩阵#include "BFS.h"void BFT(const Matrix <bool> &G, vector <int> &Visited) { // 从顶点0开始,已访问的顶点标记为Visited[i]=分支中的// 访问序号,Visited各分量已经初始化为0。
int n = G.Rows(); // 顶点个数for(int i = 0; i < n; ++i)if(!Visited[i]) BFS(G, i, Visited);}连通图的深度优先搜索(DFS):#include "Algorithm.hpp"#include "Matrix.h" // 用于邻接矩阵void DFS(const Matrix <bool> &G, int v, vector<int> &Visited, int k = 1) { // 访问由v到达的所有顶点,起始下标为0int n = G.Rows();Visited[v] = k;for(int w = 0; w < n; ++w)if(Visited[w] == 0 && G[v][w] == 1)DFS(G, w, Visited, k + 1);}归并排序算法:#include "Algorithm.hpp"template <class T> // 合并两个有序组到wvoid Merge(T a[], int low, int mid, int high, T w[]){ // 将有序组a[low .. mid]和a[mid+1 .. high]合并到有序组w[low .. high] int i = low, j = mid + 1, k = low; // low组游标i,high组游标j,结果游标k for(; i <= mid && j <= high; ++k) // 当两组都未取尽时if(a[i] <= a[j]) w[k] = a[i], ++i;else w[k] = a[j], ++j;// 当low组取尽,而high组未取尽时,w[k .. high] = a[j .. high]if(i > mid) copy(a + j, a + high + 1, w + k);// 当high组取尽,而low组未取尽时,w[k .. high] = a[i .. mid]else copy(a + i, a + mid + 1, w + k);}快速排序算法// Partition.h#pragma oncetemplate <class T> // 划分程序int Partition(T a[], int low, int high){ // 待划分数组为a[low .. high]。
将<key的元素置于key左侧。
int pivot = low; // 划分位置T key = a[pivot]; // 划分元素for(int i = low + 1; i <= high; ++i)if(a[i] < key) a[pivot] = a[i], ++pivot, a[i] = a[pivot];// 将小于key的元素插入key左侧,大于key的元素向右移。
a[pivot] = key; // 划分位置的元素为key。
return pivot;}#include "Partition.h"#include "Algorithm.hpp"template <class T> //void QuickSort(T a[], int low, int high){ if(low >= high) return;int pivot = Partition(a, low, high); // 划分元素的位置QuickSort(a, low, pivot - 1);QuickSort(a, pivot + 1, high);} //采用划分的选择算法#include "Partition.h"#include "Algorithm.hpp" mtemplate <class T> //T PartSelect(T a[], int n, int k){ // 在数组a[0..(n-1)]中找第k(1≤k≤n)小元素,即a[k-1]。
// 其余元素按划分元素为a[k-1]的划分规则存放。
int low = 0, high = n - 1, m; // low为起始下标,high为终止下标for(--k;;) // 保证0≤k≤n-1{ m = Partition(a, low, high); // m是第m(0≤m≤n-1)小元素的位置if(k == m) return a[m];else if(k < m) high = m - 1; // 新的终止下标为m-1else low = m + 1; // 新的起始下标为m+1}}CH4背包问题背包问题的贪心算法template <class Tv, class Tw, class T> //void GreedyKNAP(Tv V[], Tw W[], T X[], int n, Tw rc){ // V是价值数组,W是重量数组,X是解向量,rc是剩余容量。
int i;fill(X, X + n, 0); // 解向量初始化为零mSort(V, W, n, Comp<Tv, Tw>); // 将物品按单价降序排列for(i = 0; i < n && W[i] <= rc; ++i)X[i] = 1, rc = rc - W[i]; // 可完整装包的物品完整装包if(i < n) X[i] = rc / W[i]; // 不能完整装包的物品部分装包}2 种最小生成树算法Prim 算法// Prim.h#include "Matrix.h"template <class W> //bool Prim(const Matrix<W> &G, Matrix<int> &T){ // G是邻接矩阵。
T存放生成树的边,共n-1行2列。
int i, j, k, n = G.Rows();W minCost = 0; // 刚开始时最小生成树的成本值为0vector<int> near(n, 0); // 指定各顶点的初始near值near[0] = -1; // 将0加到树中for(i = 0; i < n - 1; ++i) // 循环n-1次, 添加n-1条边{ // 求树外顶点到树内顶点具有最小权值的边及顶点位置jW min = Matrix<W>::inf; // 无穷大for(j = 0, k = 1; k < n; ++k)if(near[k] >= 0 && G[near[k]][k] < min) min = G[near[k]][k], j = k;if(min >= Matrix<W>::inf) return false; // min是无穷大,没有生成树T[i][0] = near[j], T[i][1] = j; // 添加(near[j], j),其中j是near[j]的儿子minCost += min; // 添加(near[j], j)后,树的成本值增加near[j] = -1; // 将j加到树中for(k = 1; k < n; ++k) // 更新每个顶点的near值if(near[k] >= 0 && G[j][k] < G[near[k]][k]) near[k] = j;6} //return true; // 共找到n-1条,有生成树}Kruskal算法template <class Ty> //bool Kruskal(Edge <Ty> Ed[], int n, int e, Edge <Ty> T[]){ UnionFind U(n); // 合并/查找结构,初始时表示n个不同集合sort(Ed, Ed + e); // 对边集合排序int i, k;for(i = 0, k = 0; i < e && k < n - 1; ++i){ int a = U.Find(Ed[i].u), b = U.Find(Ed[i].v); // u,v所在集合if(a != b) // 如果u、v分属不同集合,选取该边{ T[k] = Ed[i], ++k; // 将边x加入最小生成树,边数增加1U.Union(a, b); // 合并u、v分属的两个集合}}return k == n - 1; // 是否有最小生成树}Dijkstra 最短路径算法#include "Algorithm.hpp"#include "Matrix.h"template<class T> // G是有向图的邻接矩阵,v是指定顶点void Dijkstra(const Matrix<T> &G, int v, vector<T> &dist, vector<int> &Prev) {int i, u, w, n = G.Rows();vector<bool> S(n, 0); // 标志一个顶点是否属于S,初始化为0for(i = 0; i < n; ++i) dist[i] = G[v][i], Prev[i] = v; // 初始化dist,Prevdist[v] = 0, S[v] = 1; // v加入Sfor(i = 0; i < n - 1; ++i){ // 选取w使Dist(w)=min{Dist(u)|S(u)=0}for(w = 0; w < n && S[w] == 1; ++w) {} // 第一个满足S(w)=0的wfor(u = w; u < n; ++u) // 找到满足要求的wif(S[u] == 0 && dist[u] < dist[w])w = u;S[w] = 1; // w加入Sfor(u = 0; u < n; ++u) // 更新未选顶点的dist和Previf(S[u] == 0 && G[w][u] < dist[u] && dist[w] + G[w][u] < dist[u])dist[u] = dist[w] + G[w][u], Prev[u] = w;}} //CH5矩阵连乘问题的解法1、计算矩阵连乘的递归算法计算最优值#include "Algorithm.hpp"#include "Matrix.h"int MatrixChain1(int r[], Matrix<int> &kay, int i = 0, int j = -1){ if(j < 0) j = kay.Rows() - 1; // 初始化,j=n-1if(j <= i) return 0; // 只有一个矩阵// 有多个矩阵,从k=i开始计算最小项u,并更新kay#define C(i, j) MatrixChain1(r, kay, (i), (j))int u = C(i, i) + C(i + 1, j) + r[i] * r[i + 1] * r[j + 1];kay[i][j] = i;for(int k = i + 1; k < j; ++k){ int t = C(i, k) + C(k + 1, j) + r[i] * r[k + 1] * r[j + 1];if(t < u) u = t, kay[i][j] = k; // 找到更小的项}return u;#undef C}求矩阵连乘最优次序的备忘录方法int MatrixChain2(int r[], Matrix<int> &kay, Matrix<int> &c, int i = 0, int j = -1) { if(j < 0) j = kay.Rows() - 1, fill(c.begin(), c.end(), 0); // 初始化,j=n-1if(j <= i) return 0; // 只有一个矩阵if(c[i][j] > 0) return c[i][j]; // c[i][j]已经确定// 有多个矩阵,从k=i开始计算最小项u,并更新kay#define C(i, j) MatrixChain2(r, kay, c, (i), (j))c[i][j] = C(i, i) + C(i + 1, j) + r[i] * r[i + 1] * r[j + 1];kay[i][j] = i;for(int k = i + 1; k < j; ++k){ int t = C(i, k) + C(k + 1, j) + r[i] * r[k + 1] * r[j + 1];if(t < c[i][j]) c[i][j] = t, kay[i][j] = k; // 找到更小的项}return c[i][j];#undef c}求矩阵连乘最优次序的动态规划算法int MatrixChain3(int r[], Matrix<int> &kay, Matrix<int> &c){ int i, j, k, t, n = kay.Rows(); // 动态规划方法,n为矩阵个数fill(c.begin(), c.end(), 0); // 初始化for(i = n - 2; i >= 0; --i) // 计算c[i][j]和kay[i][j],其中j>i{ for(j = i + 1; j < n; ++j) // 从k=i开始计算最小项u,并更新kay{ c[i][j] = c[i][i] + c[i + 1][j] + r[i] * r[i + 1] * r[j + 1], kay[i][j] = i;for(k = i + 1; k < j; ++k){ t = c[i][k] + c[k + 1][j] + r[i] * r[k + 1] * r[j + 1];if(t < c[i][j]) c[i][j] = t, kay[i][j] = k; // 找到更小的项}}}return c[0][n - 1];}任意顶点间最短路径#include "Algorithm.hpp"#include "Matrix.h"template <class T, class Func> // 顶点编号从0开始Matrix<T> Floyd(const Matrix<T> &Cost, Matrix<int> &Next, Func Plus) { int i, j, k, n = Cost.Rows();Matrix<T> A = Cost; // A[-1]=Costfor(i = 0; i < n; ++i)for(j = 0; j < n; ++j)Next[i][j] = j; // 建立初始Next55for(k = 0; k < n; ++k) //A[0]到A[n-1]的循环控制for(i = 0; i < n; ++i)for(j = 0; j < n; ++j){ if(i == k || j == k) continue;T x = Plus(A[i][k], A[k][j]);if(x < A[i][j]) A[i][j] = x, Next[i][j] = Next[i][k];}return A;}CH6子集问题递归方法(一)#include "Algorithm.hpp"#define legal(t) true // 检查合法性#define bound(t) true // 检查界限void Subset1(int X[], int n, int t = 0) // 递归方法(一){ for(int i = 0; i <= 1; ++i){ X[t] = i;if(!legal(t)) continue; // not legalif(t >= n - 1) Copy(X, X + n) << endl; // answerelse if(bound(t)) Subset1(X, n, t + 1); // bound}}递归方法(二)void Subset2(int X[], int n, int t = 0) // 递归方法(二){ if(t >= n) Copy(X, X + n) << endl; // answerelse{ X[t] = 1; // 尝试选取t,生成左儿子if(legal(t)) Subset2(X, n, t + 1); // legalX[t] = 0; // 若根t子树没有越界,生成右儿子if(bound(t)) Subset2(X, n, t + 1); // bound}}迭代方法void Subset(int X[], int n) // 迭代方法{ X[0] = - 1;for(int t = 0; t >= 0;){ ++X[t];if(X[t] > 1) --t; // 回溯else if(!legal(t)) continue; // not legalelse if(t >= n - 1) Copy(X, X + n) << endl; // answer else if(bound(t)) ++t, X[t] = - 1; // bound}}排列问题递归方法(一)#include "Perm.h"#include "Algorithm.hpp"#define legal(X, t) true // 检查合法性#define bound(X, t) true // 检查界限void Perm1(int X[], int n, int t = 0) // 生成分量的方法{ if(t <= 0) fill(X, X + n, -1); // X初始化为-1,必须while(NextValue(X, n, t))if(legal(X, t))if(t >= n - 1) Copy(X, X + n) << endl; // 已经获得一个排列else if(bound(X, t)) Perm1(X, n, t + 1); // 纵深搜索}递归方法(二)void Perm2(int X[], int n, int t = 0) // 对自然排列重新排列的方法{ if(t <= 0) InitPerm(X, n); // 初始化为0..(n-1)的自然排列,必须for(int i = t; i < n; ++i){ swap(X[t], X[i]);if(legal(X, t))if(t >= n - 1) Copy(X, X + n) << endl; // 已经获得一个排列else if(bound(X, t)) Perm2(X, n, t + 1); // 纵深搜索swap(X[t], X[i]);}}迭代方法void Perm(int X[], int n) // 用迭代方法生成各个分量{ int t = 0;X[t] = -1;while(t >= 0){ if(!NextValue(X, n, t)) --t; // 回溯else if(legal(X, t))if(t >= n - 1) Copy(X, X + n) << endl; // 已经获得一个排列else if(bound(X, t)) ++t, X[t] = -1; // 纵深搜索}}旅行商问题递归方法(一)#include "Algorithm.hpp"#include "Perm.h"#include "Matrix.h"#include "TSP.h"template <class T> // BX为最优路径,BC为最优耗费,C为当前耗费void TSP1(Matrix<T> &G, int BX[], T &BC, T C = 0, int t = 1){ static int n, *X; // n为图的顶点个数。