算法學習-分治法

設計思想

對於規模爲n的問題,如果可以直接解決就解決,否則將其分爲k個規模較小的問題,這些子問題相互獨立並且和原來問題的形式相同,遞歸地解決這些子問題,之後再將子問題的解合併得到原問題的解

分治法常常採用遞歸的技術,每一層遞歸上都有三個步驟

  1. 分解
  2. 求解子問題
  3. 合併

快速排序的例子

快速排序的思想就是選一個基準(通常是首項),把比它小的排到它前面,比它大的排到它後面,這稱作一次劃分,然後對兩個子序列再做劃分,直到子序列裏只有一個元素或者爲空

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;
}

求解最大連續子列和問題的例子

將子列從中間開始分爲兩個部分,那麼最大連續子列的出現就有三種情況

  1. 完全在mid的左邊
  2. 完全在mid的右邊
  3. 從左到右跨過了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); 
} 

 

發佈了11 篇原創文章 · 獲贊 19 · 訪問量 7257
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章