算法原理与分析之分治法

来源:互联网 发布:牛仔质量好的品牌 知乎 编辑:程序博客网 时间:2024/05/16 12:14

一.目录

1.算法基本原理

2.经典问题

二.分治法基本原理

    分而治之,先将原问题的规模下降,分解为子问题,此所谓“分”,然后解决子问题,此为“治”。

    分治法的基本思想是将一个规模为n的原问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题相同。递归地解这些子问题,然后将子问题的解合并为原问题的解。

     分治法的伪代码:

   v divide_and_conquer(proplem p){//n为问题规模

       if(|p|<n0)//n0为一阈值

       solve(p);

     else{

      divide p into smaller subproblem P1,P2,...Pk;

      for(i=1;i<=k;i++){

       yi=divide_and_conquer(Pi);

      return merge(y1,y2,...,yk);

}

}

}

   可以看到,分治法与递归是一对孪生兄弟,有分治法的地方就有递归的身影。

    使用分治法时,要将原问题进行规模分解,分解为独立的子问题。一般来说,将原问题分解为两个大小相同的子问题可以得到将好的效率。 

    对分治法的复杂度分析是通过对递归的复杂度进行分析。递归复杂度分析方法有三种,即主定理,递归树,代入法。


三.经典问题

  3.1.合并排序

  3.2.快速排序

  3.3.线性时间选择


 3.1合并排序 

     合并排序是利用分治法对n个元素进行排序的方法。其基本思想,先将原元素集合分解为规模大小基本相同的两个子集合,然后依次递归地对子问题进行排序。最后将排好序的子集合合并为所要求的排好序的集合。

    伪代码:

    void merge_sort(Type a[],int left,int right){

      if(left<right){    //至少两个元素

         int i = (left+right)/2;

        merge_sort(a,left,i);

        merge_sort(a,i+1,right);

        merge(a,b,left,i,right);//合并到数组b

        copy(a,b,left,right);//复制回数组a

}

}

     void merge(Type origin[],Type destint[],int left,int middle,int right){

          int i=left; int k=left; int j=middle+1;

         while(i<middle &&  j<right){

               if(origin[i]<origin[j]) destin[k++] = origin[i++];

              else  destin[k++] = origin[j++];

  }

      //处理剩余元素

         if(i<middle){

          while(i<middle) destin[k++] = origin[i++];

         else

         while(j<right) destin[k++] = origin[j++];

}

  }

   分治法的复杂度分析:

       分治法的递归语句复杂度为T(n/2);

       合并(merge) n个元素的复杂度为O(n);

      复制(copy) n个元素的复杂度为O(n);

                               O(1) n<=1;

               T(n) ={

                              T(n/2) + O(n); n>=2;

   可以得出分治法的平均复杂度为O(nlogn);

   

1 0