算法学习-分治法

设计思想

对于规模为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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章