第四章
分治策略
在分治策略中我们将递归的求解一个问题,在每层递归中有如下三个步骤。
分解 将问题划分为一些子问题,子问题形式与原问题一样,只是规模更小。
解决 递归的求解出子问题。如果子问题规模足够小,则停止递归,直接求
解。
合并 将子问题的解合并为原问题的解。
需要递归求解时,我们称之为
递归情况,当子问题足够小时,不需要递归时,
我们称之为递归已经
触底,进入基本情况。
递归式
一个递归式就是一个不等式或等式,通过更小的输入来描述一个函数。
三种求解递归式的方法
代入法 猜测一个界,并用数学归纳法证明。
递归树法 将递归式转换为一棵树,其节点表示不同层次的递归调用后产生的
代价。然后采用边界技术来求解递归式。
主方法 T(n) = aT(n/b)+f(n)
最大子数组问题
分治策略求解方法
分析
可以将数组分为两个子数组,那么最大子数组一定在前一个子数组中或后一个子数组中
或经过两子数组中间。
可以递归的求解各子数组最大子数组,最后合并问题得出原问题最大子数组。
原书伪代码(查找经过前后子数组的最大子数组 即中间情况)
FIND-MAX-CROSSING-SUBARRY(A,low,mid,high) left-sum = -∞ //左子数组最大子数组之和 sum = 0 for i = mid downto low //查找经过中间项的最大左子数组 sum = sum + A[i] if sum > left-sum left-sum = sum max-left = i right-sum = -∞ //右子数组最大子数组之和 sum = 0 for j = mid + 1 to high //查找经过中间项的最大右子数组 sum = sum + A[j] if sum > right-sum right-sum = sum max-right = j return(max-left,max-right,left-sum + right-sum) //合并即为最大中间子数组
C语言实现(例 查找一个10项数组的最大子数组)
#include<stdio.h> #include<stdlib.h> typedef struct{ int leftmax1; int rightmax1; int maxsum1; }mystruct; //定义结构体用来存储最大子数组 mystruct midmax(int a[],int low,int mid,int high) //结构体函数传递每层递归最大中间子数组 { mystruct midside; //最大中间子数组 int sum,i,j; int leftmax,rightmax,maxsum,max = 0; sum = 0; maxsum = -100; for(i = mid;i >=low;i--) //查找经过中间项最大左子数组 { sum = sum+a[i]; if(sum > maxsum) { maxsum = sum; leftmax = i; } } max = max+maxsum; sum = 0; maxsum = -100; for(j = mid+1;j<=high;j++) //查找经过中间项最大右子数组 { sum = sum+a[j]; if(sum>maxsum) { maxsum = sum; rightmax = j; } } max = max+maxsum; //确定最大中间子数组 midside.leftmax1 = leftmax; midside.rightmax1 = rightmax; midside.maxsum1 = max; return midside; } mystruct digui(int a[],int low,int high) //递归部分 { mystruct answer; mystruct leftside; mystruct rightside,midside; int mid = 0; if(low == high) //触底情况,即基本情况,直接给出答案 { answer.leftmax1 = low; answer.rightmax1 = high; answer.maxsum1 = a[low]; return answer; } else{ mid = (low+high)/2; leftside = digui(a,low,mid); rightside = digui(a,mid+1,high); midside = midmax(a,low,mid,high); if(leftside.maxsum1 >= rightside.maxsum1&&leftside.maxsum1 >= midside.maxsum1) return leftside; else if(rightside.maxsum1 >= leftside.maxsum1&&rightside.maxsum1 >= midside.maxsum1) return rightside; else if(midside.maxsum1 >= rightside.maxsum1&&midside.maxsum1 >= leftside.maxsum1) return midside; } //比较每层左最大子数组,右最大子数组,中间最大子数组,确定该层最大子数组 } int main() { mystruct answer; int a[10]; a[0] = 7; a[1] = 5; a[2] = -4; a[3] = 0; a[4] = -3; a[6] = 1; a[7] = -2; a[8] = 3; a[9] = 3; answer = digui(a,0,9); //调用函数 printf("\n %d\n",answer.maxsum1); return 0; }