算法导论学习之分治法

来源:互联网 发布:试卷出题软件 编辑:程序博客网 时间:2024/06/05 18:39

 分治法的主要思想为将一个大问题转换成一个小问题,再解决每个小问题。主要分为三个步骤:

         1、Devide——大问题分解成小的问题

         2、Conquer——(递归地)解决小问题

         3、Combine——将解合并

下面介绍一些比较常见的运用分治思想的算法。

一、归并排序

        归并排序是性能比较好的一种排序方法,它的时间复杂度是O(nlgn),是典型的运用了分治思想的算法。归并排序的步骤如下:

1、分解。将待排序的n个元素分解成n/2的子序列。

2、解决。使用归并排序递归的排列两个子序列。

3、合并。将两个已排序的子序列合并得出结果。

代码如下:

//将有二个有序数列a[first...mid]和a[mid...last]合并。  void mergearray(int a[], int first, int mid, int last, int temp[])  {      int i = first, j = mid + 1;      int m = mid,   n = last;      int k = 0;            while (i <= m && j <= n)      {          if (a[i] <= a[j])              temp[k++] = a[i++];          else              temp[k++] = a[j++];      }            while (i <= m)          temp[k++] = a[i++];            while (j <= n)          temp[k++] = a[j++];            for (i = 0; i < k; i++)          a[first + i] = temp[i];  }  void mergesort(int a[], int first, int last, int temp[])  {      if (first < last)      {          int mid = (first + last) / 2;          mergesort(a, first, mid, temp);    //左边有序          mergesort(a, mid + 1, last, temp); //右边有序          mergearray(a, first, mid, last, temp); //再将二个有序数列合并      }  }  

下面分析一下归并排序的时间复杂度。归并排序最坏情况运行时间T(n)的递归式如下:

常量c代表求解规模为1的问题所需的时间以及在分解与合并步骤处理每个元素所需的时间。对T(n)进行分解可得如下的树:

由d图可知,这棵树的高度为lg n,每层耗费cn,所以总代价为cn lg n+cn。忽略掉系数和低阶项后可知其时间复杂度为O(n lgn)。

二、幂次方问题

       给定一个数x(int/float),和一个正整数n,求x^n。这道题直接用循环做,很简单,但时间复杂度是O(n)。能否改进一下算法,减小时间复杂度呢,这里就要用到分治的思想了。

1、分解。x^n可以分解为x^n/2*x^n/2。

2、解决。(递归)求解每个子问题。

3、合并。将子问题合并。

代码如下:

    int flag=0;    public double myPow(double x, int n) {        if(n == 0)            return 1;        if(n<0&&flag==0){//处理n为负数时的情况            x = 1/x;            flag++;//保证这个if语句只执行一次。因为x=1/x只需要设置一次        }        return (n%2 == 0) ? myPow(x*x, n/2) : x*myPow(x*x, n/2);    }

这个算法的时间复杂度是O(lg n),比直接使用循环求解性能要好一些。

三、二分查找

      在一个有序序列A中查找元素x。这也是一个比较简单的算法,用分治法的步骤如下:

1、分解——将x与序列的中间元素比较
2、解决——(递归地)在子有序数列中查找x
3、合并——什么也不做
代码如下:
int BinarySearchRecursive(int *Array,int x,int Low,int High) //L is the length of the sorted array  {      int mid;      mid = (Low + High + 1)/2 ;        if (Low < High)      {          if (Array[mid] < x)          {              Low = mid + 1 ;              return BinarySearchRecursive(Array,x,Low,High) ;          }          else if (Array[mid] > x)          {              High = mid - 1;              return BinarySearchRecursive(Array,x,Low,High) ;          }          else              return mid ;      }      else          return -1 ;  }  
总结:分治法最重要的是将一个大问题化为一个小问题,然后各个击破的思想。它虽然是比较简单的一种算法,但如果能够真正掌握其思想并做到融会贯通,也会展现出其强悍的一面。

0 0
原创粉丝点击