《算法设计与分析》复习

《算法设计与分析》复习

  • 课后练习题
    • 练习题1
    • 练习题2
  • 参考题
    • 填空题
    • 简答题

课后练习题

练习题1

  1. 简述数据结构和算法的关系
    答:数据结构是算法的基础,算法的操作对象是数据结构, 在设计算法时需要构造适合该算法的数据结构。数据结构关注的是数据的逻辑结构,存储结构以及基本操作。而算法关注的是如何在数据结构基础上解决实际问题。

  2. 什么是算法?算法的特征有哪些?
    答:算法是求解问题的一系列计算步骤,用来将输入数据转换成输出结果。算法具有五个特征: 有限性、确定性、可行性、输入性、输出性

  3. 证明以下关系式成立。
    (1) 10 n 2 − 2 n = ⊙ ( n 2 ) 10n^2 - 2n = \odot(n^2) 10n22n=(n2)
    证明:
    当 n ≥ 1时,因为
    8 n 2 ≤ 10 n 2 − 2 n ≤ 10 n 2 8n^2 \le10n^2-2n\le10n^2 8n210n22n10n2
    故有 10 n 2 − 2 n = ⊙ ( n 2 ) 10n^2 - 2n = \odot(n^2) 10n22n=(n2)
    (2) 2 n = ⊙ ( 2 n + 1 ) 2^n = \odot(2^{n+1}) 2n=(2n+1)
    证明:
    当 n ≥ 1时,因为
    1 2 × 2 n + 1 ≤ 2 n ≤ 2 n + 1 \frac{1}{2} \times 2^{n+1} \le2^n\le2^{n+1} 21×2n+12n2n+1
    故有 2 n = ⊙ ( 2 n + 1 ) 2^n = \odot(2^{n+1}) 2n=(2n+1)

  4. 如果有 T 1 ( n ) = ◯ ( f ( n ) ) T_{1}(n)=\bigcirc(f(n)) T1(n)=(f(n)) T 2 ( n ) = ◯ ( g ( n ) ) T_{2}(n)=\bigcirc(g(n)) T2(n)=(g(n))证明下列等式成立
    T 1 ( n ) + T 2 ( n ) = M A X { ◯ ( f ( n ) ) , ◯ ( g ( n ) ) } T_{1}(n)+T_{2}(n)=MAX\{ \bigcirc(f(n)),\bigcirc(g(n)) \} T1(n)+T2(n)=MAX{(f(n)),(g(n))} T 1 ( n ) × T 2 ( n ) = ◯ ( f ( n ) × g ( n ) ) T_{1}(n) \times T_{2}(n)=\bigcirc(f(n)\times g(n)) T1(n)×T2(n)=(f(n)×g(n))
    证明:因为 T 1 ( n ) = ◯ ( f ( n ) ) T_{1}(n) = \bigcirc(f(n)) T1(n)=(f(n))故存在n1,C1,当n ≥ n1时,有 T 1 ( n ) ≤ C 1 f ( n ) T_{1}(n) \le C_{1}f(n) T1(n)C1f(n)又因为 T 2 ( n ) = ◯ ( g ( n ) ) T_{2}(n)=\bigcirc(g(n)) T2(n)=(g(n))故存在n2,C2,当n ≥ n2时,有 T 2 ( n ) ≤ C 2 g ( n ) T_{2}(n) \le C_{2}g(n) T2(n)C2g(n)令n3 = max (n1 , n2) 、 C3 = max (C1 , C2) ,
    则,当n ≥ n3 时,有 T 1 ( n ) ≤ C 3 f ( n ) T_{1}(n) \le C_{3}f(n) T1(n)C3f(n) T 2 ( n ) ≤ C 3 g ( n ) T_{2}(n) \le C_{3}g(n) T2(n)C3g(n)故有 T 1 ( n ) + T 2 ( n ) ≤ C 3 f ( n ) + C 3 g ( n ) T_{1}(n) + T_{2}(n) \le C_{3}f(n)+C_{3}g(n) T1(n)+T2(n)C3f(n)+C3g(n) = C 3 ( f ( n ) + g ( n ) ) =C_{3}(f(n)+g(n)) =C3(f(n)+g(n)) ≤ 2 m a x { f ( n ) , g ( n ) } \le 2max\{ f(n),g(n)\} 2max{f(n),g(n)}所以 T 1 ( n ) + T 2 ( n ) = ◯ ( m a x { f ( n , g ( n ) ) } ) T_{1}(n) + T_{2}(n)=\bigcirc ( max\{ f(n,g(n))\} ) T1(n)+T2(n)=(max{f(n,g(n))}) = m a x ( ◯ ( f ( n ) ) , ◯ ( g ( n ) ) ) =max(\bigcirc(f(n)),\bigcirc(g(n))) =max((f(n)),(g(n)))另:因为当n ≥ n3时 T 1 ( n ) × T 2 ( n ) ≤ C 3 f ( n ) × C 3 g ( n ) = C 3 2 f ( n ) × g ( n ) T_{1}(n) \times T_{2}(n)\le C_{3}f(n) \times C_{3}g(n)=C_{3}^2f(n)\times g(n) T1(n)×T2(n)C3f(n)×C3g(n)=C32f(n)×g(n) T 1 ( n ) × T 2 ( n ) = ◯ ( f ( n ) × g ( n ) ) T_{1}(n)\times T_{2}(n)=\bigcirc (f(n)\times g(n)) T1(n)×T2(n)=(f(n)×g(n))

  5. T ( n ) = a m n m + a m − 1 n m − 1 + . . . + a 1 n + a 0 T(n)=a_{m}n^m+a_{m-1}n^{m-1}+...+a_{1}n+a_{0} T(n)=amnm+am1nm1+...+a1n+a0证明 T ( n ) = ◯ ( n m ) T(n)=\bigcirc(n^m) T(n)=(nm)
    证明:当n ≥ 1时,有
    T ( n ) = a m n m + a m − 1 n m − 1 + . . . + a 1 n + a 0 ≤ ∣ a m ∣ n m + ∣ a m − 1 ∣ n m − 1 + . . . ∣ a 1 ∣ n + ∣ a 0 ∣ ≤ ( ∣ a m ∣ + ∣ a m − 1 ∣ + . . . + ∣ a 1 ∣ + ∣ a 0 ∣ ) n m \begin{aligned} T(n)&=a_{m}n^m+a_{m-1}n^{m-1}+...+a_{1}n+a_{0}\\&\le\left|a_{m}\right|n^m+\left|a_{m-1}\right|n^{m-1}+...\left|a_{1}\right|n+\left|a_{0}\right|\\&\le(\left|a_{m}\right|+\left|a_{m-1}\right|+...+\left|a_{1}\right|+\left|a_{0}\right|)n^m \end{aligned} T(n)=amnm+am1nm1+...+a1n+a0amnm+am1nm1+...a1n+a0(am+am1+...+a1+a0)nm
    T ( n ) = ◯ ( n m ) T(n)=\bigcirc(n^m) T(n)=(nm)

  6. 【3n+1问题】 从整数n开始,如果n为偶数,把它除以二;如果n为奇数,把它乘3加1。用新得到的值重复上述步骤,直到n = 1时停止。例如 n = 22时得到的序列时22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1。对于任意整数n,该算法总能终止于n = 1,这个猜测对于至少1 000 000 内的整数都是正确的。对于给定的n,该序列的元素(包括1)个数称为 n 的循环节长度。请计算 i 到 j (包含 i 和 j )之间的整数中,循环节长度的最大值。
    输入:每行包含两个整数 i 和 j 。所有整数大于0,小于1 000 000。
    输出:对于每对整数 i 和 j ,按原来的顺序输出 i 和 j ,然后输出两者之间的整数中的最大循环节长度,它们之间用单个空格分隔,且在同一行输出。对于读入的每一组数据,在输出中应位于单独的一行。
    输入样本:
    1 10
    100 200
    201 210
    900 1000
    输出结果:
    1 10 20
    100 200 125
    201 210 89
    900 1000 174

    #include
    int cycle(int i,int j)
    //求i到j之间的整数中,3n+1问题循环节长度的最大值
    {
    	int k,count,maxc;
    	//k从i变化到j,并求k的循环节,count是循环节计数器,maxc存放循环节的最大值
    	maxc = 0;
    	for(k = i;k <= j;k++)
    	{
    		count = 0;
    		while(k != 1)
    		{
    			//循环不结束
    			if(k % 2 == 0)
    				k = k / 2;
    			else
    				k = 3 * k + 1;
    			count++;
    		}
    		if(maxc < count)
    			maxc = count;
    	}
    	return maxc;
    }
    

练习题2

  1. 什么是直接递归和间接递归,消除递归要用到什么数据结构?
    答:一个过程或函数调用了自身,称为直接递归;
    若过程或函数P调用过程或函数Q,而且Q又调用P,则称间接递归;
    消除递归一般用到栈结构。

  2. 分析以下程序的执行结果:

    #include
    void f(int n,int &m)if(n < 1)
       	return;
       else
       {
       	printf("调用f( %d , %d )前,n = %d,m = %d\n",n-1,m-1,n,m);
       	n--;m--;
       	f(n-1,m);
       	printf("调用f( %d , %d )后,n = %d,m = %d\n",n-1,m-1,n,m);
       }void main()
    {
       int n = 4,m = 4;
       f(n,m);
    }
    

    答:该程序的执行结果如下:
    调用f(3,3)前,n = 4,m = 4
    调用f(1,2)前,n = 2,m = 3
    调用f(0,1)后,n = 1,m = 2
    调用f(2,1)后,n = 3,m = 2

  3. 某递归算法的执行时间T(n)有以下递推关系: T ( n ) = { 1 n = 1 T ( n 3 ) + T ( 2 n 3 ) n > 1 T(n)=\left\{ \begin{array}{rcl} 1 & & {n = 1}\\ T(\frac{n}{3})+T(\frac{2n}{3}) & & {n>1} \end{array} \right. T(n)={1T(3n)+T(32n)n=1n>1求该算法的时间复杂度。

    令C表示 ◯ ( n ) \bigcirc(n) (n)项中的常数因子,构造递归树如下
    每次的代价均为 C n Cn Cn,从根结点到叶结点的最长路径是
    n → ( 2 3 ) n → ( 2 3 ) 2 n → . . . → 1 n → (\frac{2}{3})n → (\frac{2}{3})^2n → ... → 1 n(32)n(32)2n...1 即右子树
    ( 2 3 ) k n = 1 (\frac{2}{3})^kn = 1 (32)kn=1,则 k = log ⁡ 3 2 n k = \log_\frac{3}{2}n k=log23n,k为树高
    假设该递归树是完全二叉树,且每行的代价为 C n Cn Cn,则 T ( n ) ≤ C n × log ⁡ 3 2 n T(n) \le Cn \times \log_\frac{3}{2}n T(n)Cn×log23n T ( n ) = ◯ ( n l o g n ) T(n) = \bigcirc(nlogn) T(n)=(nlogn)
    但该树的左子树高度较低,左子树序列为 n → 1 3 n → ( 1 3 ) 2 n → . . . → 1 n → \frac{1}{3}n → (\frac{1}{3})^2n → ... → 1 n31n(31)2n...1树高为 log ⁡ 3 n \log_3n log3n,故有 T ( n ) ≥ ( 最 左 边 叶 子 所 做 的 工 作 ) + C n × log ⁡ 3 n T(n) \ge (最左边叶子所做的工作) + Cn \times \log_3n T(n)()+Cn×log3n记最左边叶子所做的工作为 T 1 T1 T1,则
    T ( n ) ≥ T 1 × 2 log ⁡ 3 n + C n × log ⁡ 3 n = T 1 × n log ⁡ 3 2 + C n × log ⁡ 3 n ≈ T 1 × n 1.6 + C n × log ⁡ 3 n = Ω ( n l o g n ) \begin{aligned} T(n) &\ge T1 \times 2^{\log_3n} + Cn \times \log_3n\\&= T1 \times n^{\log_32} + Cn \times \log_3n\\&\approx T1 \times n^{1.6} + Cn \times \log_3n\\&= \varOmega (nlogn) \end{aligned} T(n)T1×2log3n+Cn×log3n=T1×nlog32+Cn×log3nT1×n1.6+Cn×log3n=Ω(nlogn) T ( n ) = Θ ( n l o g n ) T(n) = \varTheta(nlogn) T(n)=Θ(nlogn)

参考题

填空题

  1. 使用二分搜索算法在n个有序元素中,在最佳情况下,搜索的时间复杂度为 ◯ ( 1 ) \bigcirc(1) (1),在最坏的情况下,搜索的时间复杂度为 ◯ ( log ⁡ 2 n ) \bigcirc(\log_2n) (log2n)
  2. 大整数乘积算法是用分治法来设计的
  3. 以深度优先方式系统搜索问题解空间的算法称为回溯法
  4. 回溯法的两种结构
    1.子集树结构: 0/1背包问题
    2.排列树结构: 批处理作业调度、旅行售货员
  5. 贪心算法的基本要素是:贪心选择性质最优子结构性质
  6. 冒泡排序算法属于穷举法
  7. 问题的最优子结构性质是该问题可用动态规划算法和贪心算法求解的关键特征
  8. 动态规划算法的两个基本要素是最优子结构性质重叠子问题性质
  9. 分支限界法使用广度优先遍历或者最小消耗优先方式来搜索解空间树
  10. 回溯法使用深度优先方式来搜索解空间树
  11. 分支限界法主要有队列式(FIFO)分支限界法和优先队列式分支限界法
  12. 解决0 / 1背包问题的三种方法中,需要排序的是回溯法分支限界法,不需要排序的是动态规划

简答题

  1. f ( n ) = ◯ ( g ( n ) ) f(n) = \bigcirc(g(n)) f(n)=(g(n))
    答: f ( n ) = ◯ ( g ( n ) ) f(n) = \bigcirc(g(n)) f(n)=(g(n))当且仅当存在正常量 c c c n 0 n_0 n0,使得当 n ≥ n 0 n \ge n_0 nn0时,有 f ( n ) ≤ c g ( n ) f(n) \le cg(n) f(n)cg(n),即 g ( n ) g(n) g(n) f ( n ) f(n) f(n)的上界
  2. f ( n ) = Ω ( g ( n ) ) f(n) = \varOmega(g(n)) f(n)=Ω(g(n))
    答: f ( n ) = Ω ( g ( n ) ) f(n) = \varOmega(g(n)) f(n)=Ω(g(n))当且仅当存在正常量 c c c n 0 n_0 n0,使得 n ≥ n 0 n \ge n_0 nn0时,有 f ( n ) ≥ c g ( n ) f(n) \ge cg(n) f(n)cg(n),即 g ( n ) g(n) g(n) f ( n ) f(n) f(n)的下界
  3. f ( n ) = Θ ( g ( n ) ) f(n) = \varTheta(g(n)) f(n)=Θ(g(n))
    答: f ( n ) = Θ ( g ( n ) ) f(n) = \varTheta(g(n)) f(n)=Θ(g(n))当且仅当存在正常量 c 1 c1 c1 c 2 c2 c2 n 0 n_0 n0,使得 n ≥ n 0 n \ge n_0 nn0时,有 c 1 g ( n ) ≤ f ( n ) ≤ c 2 g ( n ) c1g(n) \le f(n) \le c2g(n) c1g(n)f(n)c2g(n),即即 g ( n ) g(n) g(n) f ( n ) f(n) f(n)同阶
  4. 采用直接推导方法求解下列递归方程:
    T ( n ) = { 1 当 n = 1 T ( n − 1 ) + n 当 n > 1 T(n)= \begin{cases} 1& \text{当 n = 1}\\ T(n-1)+n& \text{当 n > 1} \end{cases} T(n)={1T(n1)+n n = 1 n > 1
    解: T ( n ) = T ( n − 1 ) + n = [ T ( n − 2 ) + n − 1 ] + n = T ( n − 2 ) + n + ( n − 1 ) = T ( n − 3 ) + n + ( n − 1 ) + ( n − 2 ) . . . = T ( 1 ) + n + ( n − 1 ) + . . . + 2 = n + ( n − 1 ) + ( n − 2 ) + . . . + 2 + 1 = n × ( n + 1 ) 2 = ◯ ( n 2 ) \begin{aligned} T(n) &= T(n - 1) + n\\ &= [T(n - 2) + n-1]+n\\ &=T(n-2) + n + (n-1)\\ &=T(n-3)+n+(n-1)+(n-2)\\ &...\\ &=T(1)+n+(n-1)+...+2\\ &=n+(n-1)+(n-2)+...+2+1\\ &=\frac{n\times (n+1)}{2}\\ &=\bigcirc(n^2) \end{aligned} T(n)=T(n1)+n=[T(n2)+n1]+n=T(n2)+n+(n1)=T(n3)+n+(n1)+(n2)...=T(1)+n+(n1)+...+2=n+(n1)+(n2)+...+2+1=2n×(n+1)=(n2)
  5. 第一数学归纳法原理:
    { P ( 1 ) , P ( 2 ) , P ( 3 ) , P ( 4 ) , . . . } \{P(1),P(2),P(3),P(4),...\} {P(1),P(2),P(3),P(4),...}是命题序列且满足以下两个性质,则所有命题均为真:
    1. P ( 1 ) P(1) P(1)为真
    2. 任何命题均可以从它的前一个命题推导得出
  6. 设有一个与正整数n有关的命题且满足以下两个性质,则命题对于一切正整数n来说都成立:
    1. 当n=1,2时,命题成立;
    2. 假设当n≤k(k∈N)时,命题成立,由此可推得当n=k+1时,命题也成立。
  7. 穷举法的基本思想: 对问题的所有可能状态一一测试,直到找到解或者将全部可能状态都测试为止
  8. 使用穷举法的几种情况:
    1. 搜索所有的解空间
    2. 搜索所有的路径
    3. 直接计算
    4. 模拟和仿真
  9. 分值法的基本思想:
    1. 将一个规模为n的问题分解为k个规模较小的子问题,这些子问题相互独立且与原问题相同,对这k个子问题分别求解。
    2. 如果子问题的规模仍然不够小,则再划分为k个子问题,如此递归下去,直到问题的规模足够小,很容易求出其解为止;
    3. 将求出的小规模问题的解合并为一个更大规模的问题的解,自底向上逐步求出原来问题的解
  10. 分治法所能解决的问题所具备的特征:
    1. 该问题的规模缩小到一定的程度就可以很容易的解决
    2. 该问题可以分解为若干个较小的相同问题
    3. 利用该问题分解出的子问题的解可以合并为该问题的解
    4. 该问题所分解的各个子问题是相互独立的,即子问题之间不包括公共子问题
  11. 二路归并排序算法 的基本思想:将待排序列元素分成大小大致相同的两个子集,按照这种方法一直进行下去,直到每个子集只有一个元素,然后自底向上逐步合并排序,最终合并成有序集合
  12. 最坏情况下的时间复杂度:
    1. 二分搜索算法: ◯ ( l o g 2 n ) \bigcirc(log_2n) (log2n)
    2. 快速排序算法: ◯ ( n 2 ) \bigcirc(n^2) (n2)
    3. 线性时间选择算法: ◯ ( n ) \bigcirc(n) (n)
  13. 贪心法 的基本思想:在对问题求解时总是做出在当前来看是最好的选择,也就是说贪心法不从整体最优上加以考虑,所做出的仅是在某种意义上的局部最优
  14. 贪心法求解问题的基本过程:
    1. 建立数学模型来描述问题
    2. 把求解的问题分成若干个子问题
    3. 对每一子问题求解,得到子问题的局部最优解
    4. 把子问题的局部最优解合并成原来问题的一个解

你可能感兴趣的:(算法设计)