设计思想
对于规模为n的问题,如果可以直接解决就解决,否则将其分为k个规模较小的问题,这些子问题相互独立并且和原来问题的形式相同,递归地解决这些子问题,之后再将子问题的解合并得到原问题的解
分治法常常采用递归的技术,每一层递归上都有三个步骤
- 分解
- 求解子问题
- 合并
快速排序的例子
快速排序的思想就是选一个基准(通常是首项),把比它小的排到它前面,比它大的排到它后面,这称作一次划分,然后对两个子序列再做划分,直到子序列里只有一个元素或者为空
f(a,s,t) = do nothing // s..t < 2
f(a,s,t) = i = partition(a,s,t)
f(a,s,i-1)
f(a,i+1,t)
int Partition(int a[],int s,int t) //划分算法
{ int i=s,j=t;
int tmp=a[s]; //用序列的第1个记录作为基准
while (i!=j) //从序列两端交替向中间扫描,直至i=j为止
{ while (j>i && a[j]>=tmp)
j--; //从右向左扫描,找第1个关键字小于tmp的a[j]
a[i]=a[j]; //将a[j]前移到a[i]的位置
while (i<j && a[i]<=tmp)
i++; //从左向右扫描,找第1个关键字大于tmp的a[i]
a[j]=a[i]; //将a[i]后移到a[j]的位置
}
a[i]=tmp;
return i;
}
求解最大连续子列和问题的例子
将子列从中间开始分为两个部分,那么最大连续子列的出现就有三种情况
- 完全在mid的左边
- 完全在mid的右边
- 从左到右跨过了mid
那么最后的结果就是三种情况下的最大值
long maxSubSum(int a[],int left,int right)
//求a[left..high]序列中最大连续子序列和
{ int i,j;
long maxLeftSum,maxRightSum;
long maxLeftBorderSum,leftBorderSum;
long maxRightBorderSum,rightBorderSum;
if (left==right) //子序列只有一个元素时
{ if (a[left]>0) //该元素大于0时返回它
return a[left];
else //该元素小于或等于0时返回0
return 0;
}
int mid=(left+right)/2; //求中间位置
maxLeftSum=maxSubSum(a,left,mid); //求左边
maxRightSum=maxSubSum(a,mid+1,right); //求右边
maxLeftBorderSum=0,leftBorderSum=0;
for (i=mid;i>=left;i--) //求出以左边加上a[mid]元素
{ leftBorderSum+=a[i]; //构成的序列的最大和
if (leftBorderSum>maxLeftBorderSum)
maxLeftBorderSum=leftBorderSum;
}
maxRightBorderSum=0,rightBorderSum=0;
for (j=mid+1;j<=right;j++) //求出a[mid]右边元素
{ rightBorderSum+=a[j]; //构成的序列的最大和
if (rightBorderSum>maxRightBorderSum)
maxRightBorderSum=rightBorderSum;
}
return max3(maxLeftSum,maxRightSum,
maxLeftBorderSum+maxRightBorderSum);
}