zoukankan      html  css  js  c++  java
  • 算法导论第三版第二章思考题答案

    2-1 (在归并排序中对小数组采用插入排序) 

    虽然归并排序的最坏情况运行时间为Θ(nlgn),而插入排序的最坏情况运行时间为Θ(n2),但是插入排序中的常量因子可能使得它在n较小时,在许多机器上实际运行得更快。因此,在归并排序中当子问题变得足够小时,采用插入排序来使递归的叶变粗是有意义的。考虑对归并排序的一种修改,
    39其中使用插入排序来排序长度为k的n/k个子表,然后使用标准的合并机制来合并这些子表,这里k是一个待定的值。

    a.证明:插入排序最坏情况可以在Θ(nk)时间内排序每个长度为k的n/k个子表。
    b.表明在最坏情况下如何在Θ(nlg(n/k))时间内合并这些子表。
    c.假定修改后的算法的最坏情况运行时间为Θ(nk+nlg(n/k)),要使修改后的算法与标准的归并排序具有相同的运行时间,作为n的一个函数,借助Θ记号,k的最大值是什么?
    d.在实践中,我们应该如何选择k?

    ******************************************************

    1)每一个大小为k的子序列最坏情况可以在O(k^2)内完成排序,则n/k个子序列可以在n/k * O(k^2) =  Θ(k^2*n/k) = O(nk)时间内完成排序。

    2)  该分治算法一共要分的层数为lg(n/k)次,而每一层,合并算法的时间复杂度为Θ(n),所以总个的时间复杂度为Θ(nlg(n/k))

    3) Θ(n*k+n*lg(n/k)) = Θ(n*lgn)

    =>Θ(k+lg(n/k)) = Θ(lgn)

    所以 k < lgn ,  k 的最大值应该是 lgn.

    4)、实践中k应该尽量选择为插入排序比合并排序快的最大的列表长度。

    伪代码:


    /**
    *参数:数组a, 起始位置,结束位置。
    **/
    void mergeSort(int a[], int p, int r)
    {
            if (r-p <= 6) { //这里的r-p +1 < = 7, 即r-p<= 6, k值为7。
                  return insertSort(a, p, r);
           } else {
                  int q = (p + r)/2;
                  mergeSort(a, p, q);
                  mergeSort(a, q+1, r);
                  merge(a, p, q, r);
           }
    }

    /**插入排序**/
    void insertSort(int a[], int p, int r)
    {
           int i, j, key;
           for (j = p+1; j <= r; j++) {
                  key = a[j];
                  i = j - 1;
                  while (i>=p && a[i]>key) {
                         a[i+1] = a[i];
                         i--;
                  }
                  a[i+1] = key;
           }
    }

    //下面是插入排序的变形。
    void insertsort(int a[], int p, int r){
           int i, j;
           for (i=p; i<r; i++)
                  for (j=i+1; j>p && a[j-1]>a[j]; j--)
                         swap(a, j, j-1); //交换数组a中的j和j-1位置处的值。
    }

    ============================================================================================================

    2-2:冒泡排序算法的正确性

    冒泡排序(bubblesort)算法是一种流行的排序算法,它重复地交换相邻两个反序元素。

    BUBBLESORT(A)

    1       for i=1 to length[A] -1
    2               for j=length[A] downto i+1
    3                       if A[j]< A[j-1]
    4                                exchange A[j]←→ A[j-1]

    a) 设A’表示BULLESORT(A)的输出,为了证明BUBBLESORT是正确的,需要证明它能够终止,并且有: A’[1]<=A[2]<=..<=A’[n]
    其中n=length[A]。为了证明BUBBLESORT的确能实现排序的效果,还需要证明什么?
    下面两个部分将证明不等式(2.3)。

    b) 对第2~4行中的for循环,给出一个准确的循环不变式,并证明该循环不变式是成立的。在证明中采用本章中给出的循环不变式证明结构。

    c) 利用在b)部分证明的循环不变式的终止条件,为第1~4行中的for循环给出一个循环不变式,它可以用来证明不等式(2.3)。你的证明因采用本章中给出的循环不变式的证明结构。

    d) 冒泡排序算法的最坏情况运行时间是什么?比较它与插入排序的运行时间。

    ******************************************************

    http://amazingidiot.iteye.com/blog/1127800

    http://ufownl.blog.163.com/blog/static/1250122200832410828987/

    http://blog.sina.com.cn/s/blog_769a9def0100tx9b.html

    a). A’中的元素全部来自于A中变换后的元素。

    b)、c) 、 答案看 http://www.cnblogs.com/ghj1976/archive/2013/03/06/2946078.html 最后一个例子的分析

    d)、最坏情况为所有数据都是从大到小排序的,这时候时间花费为Θ(n^2)。最好情况是已经排好序的,仍然是Θ(n^2),因为仍然需要双重循环。

    但是在最佳情况下,冒泡排序比插入排序略长。 

    ============================================================================================================

    2-3:霍纳规则的正确性

    NewImage

    http://blog.csdn.net/cppgp/article/details/7161701

     公式的简单推理:

    NewImage

    a0+a1*x+a2*x^2+a3*x^3+a4*x^4+…+ak*x^k+…+an*x^n

    NewImage

    计算机的循环计算。

    1      y = 0                                      时间花费  1

    2      for i=n down to 0                                   n+1

    3              y = ai + x*y                                     n

                                                                            总时间花费  2n+2

    这样循环计算出来的y就是上面汇总的值。

    a)、Θ(n), 推理过程看上面。

    b)、伪代码实现的朴素的多项式求值算法。

    NewImage








    下面是一个取巧的算法,时间消耗是 3n, 在n >2 时 时间消耗大于 2n+2

    void Ploynomial()                                  时间消耗 = 3n
    {
            int t;                                                      1
            sum = a[0];                                          1
            for (i = 1; i < n; i++)                            n
            {
                    sum += a[i]*x;                             n-1
                    x = x*x;                                         n-1
            }
    }

    c)、

    初始化: 有 y = 0, i = n , 这样 计算 下面公式的右边 为 0 , 所以初试化满足循环不变式。 

    NewImage

              

    保持:假设当第i=j满足时,考察i=j-1。

    终止: 当循环结束时候,有 i= -1,

    ------------

    由于0从0到n-(i+1),因此有:
    y = Σ ak+i+1 * x^k
      = ak+i+1 + ak+i+2 * x + ... + an * x^(n-(i+1))
    霍纳规则代码段循环不变式证明如下:
    初始:
        i=n,y[n] = 0,迭代开始时,循环后有y[n] = a[n]。
    保持:
        对于任意 0 ≤ i ≤ n,循环后有:
            y[i] = a[i] + y[i+1] * x = a[i] + (a[i+1] * x + a[i+2] * x + ... + a[n] * x^(n-(i+1))) * x
                 = a[i] + a[i+1] * x + a[i+2] * x^2 + ... + a[n] * x^(n-i)
    终止:
        i小于0时终止,此时有 y[0] = a[0] + a[1] * x + a[2] * x^2 + a[n] * x^n

    证明和y = Σ a[k+i+1] * x^k的关系:
        k 从0到n-(i+1),等价于 0 ≤ k ≤ n-(i+1)。因此
            y = Σ a[k+i+1] * x^k
                = a[i+1] + a[i+2] * x + ... + a[n-(i+1)+i+1] * x^(n-i)
                = a[i+1] + a[i+2] * x + ... + a[n] * x^(n-i)
        由于i+1循环之后和i循环之前的值相等,用y'[i]表示i循环之前的值,则有:
            y'[i] = y[i+1]
        霍纳规则循环不变式的结果表明:
            y[i] = a[i] + a[i+1] * x + a[i+2] * x^2 + ... + a[n] * x^(n-i)
        因此有:
            y'[i] = y[i+1] = a[i+1] + a[i+2] * x + ... + a[n] * x^(n-(i+1))
        令k=n-(i+1),则n=k+i+1,所以:
            y'[i] = a[i+1] + a[i+2] * x + ... + a[k+i+1] * x^(k+i+1-(i+1))
                    = a[i+1] + a[i+2] * x + ... + a[k+i+1] * x^k
        用y表示y'[i],则有:
            y = a[i+1] + a[i+2] * x + ... + a[k+i+1] * x^k
                = Σ a[k+i+1] * x^k
        其中 k从0到n-(i+1)
        证毕。


    ============================================================================================================

    2.4 逆序对
    设A[1..n]是一个包含n个不同数的数组。如果i<j且A[i]>A[j],则(i,j)就称为A中的一个逆序对(inversion)。
    a)列出数组〈2,3,8,6,1〉的5个逆序。
    b)如果数组的元素取自集合{1, 2, ..., n},那么,怎样的数组含有最多的逆序对?它包含多少个逆序对?
    c)插入排序的运行时间与输入数组中逆序对的数量之间有怎样的关系?说明你的理由。
    d)给出一个算法,它能用Θ(nlgn)的最坏情况运行时间,确定n个元素的任何排列中逆序对的数目。(提示:修改合并排序)

    a)  (2,1)  (3,1) (8,1) (6,1),(8,6)

    b) 数组从大到小有序排列时,逆序对最多,为n(n-1)/2个。

    c)

    逆序对增加时,插入排序时间增加。
    没有逆序对时,插入排序时间最少,为Θ(n)。
    逆序对最多时,插入排序时间最多,为Θ(n^2)。

    d)  归并算法, 每次移动牌,次数加1, 合计的次数就是逆序对的个数。

    NewImage

    在归并排序合并步骤时,每移动一个右边的数,查看他左边数组还剩多少数,然后将其总数相加,就可以得到逆序对的数目了。

    http://www.cnblogs.com/liao-xiao-chao/articles/2351925.html


    ============================================================================================================

    参考资料:

    http://qiemengdao.iteye.com/blog/1328678

    http://www.cnblogs.com/sinoxavier/archive/2012/11/23/2785082.html

    http://www.cnblogs.com/liao-xiao-chao/articles/2351925.html

    http://fongfc.files.wordpress.com/2009/10/alg_sol_ch_2.pdf

  • 相关阅读:
    js加密
    sharepoint更新左侧列表的名字
    HTML转换JS
    Html空格字符代码:
    docker 与host互传文件
    Ubuntu里node命令出错,找不到
    docker查看运行容器详细信息
    docker保存容器的修改
    Docker容器中安装新的程序
    运行docker容器镜像
  • 原文地址:https://www.cnblogs.com/ghj1976/p/2946460.html
Copyright © 2011-2022 走看看