設計思想
對於規模爲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);
}