算法导论之三最大子数组问题

最大子数组是数组A的和最大的非空连续子数组。只有当数组中包含负数时,最大子数组问题才有意义。注意将实际问题转化为数学问题!

使用分治策略的求解方法:

为寻找A[low..high]的最大子数组,其中央位置记为mid,然后考虑求解两个子数组A[low..mid]和A[mid+1..high]。A[low..high]的任何子数组A[i..j]所处的位置必然是以下三种情况之一:

1. 完全位于子数组A[low..mid]中,因此low <= i<= j <=mid。

2. 完全位于子数组A[mid+1..high]中,因此mid < i<= j <= high。

3. 跨越了中点,因此low <= i <= mid < j <= high。

 

实际上,A[low..high]的最大子数组必然是以上三种情况下所有子数组中的最大者。

任何跨越中点的子数组都由两个子数组A[i..mid]和A[mid+1..j]组成,只需分别找出A[i..mid]和A[mid+1..j]的最大子数组,然后将其合并即可。

以下伪代码接收数组A和下标low,mid和high作为输入,返回一个下标元组划定跨越中点的最大子数组的边界,并返回最大子数组中值的和。

FIND-MAX-CROSSING-SUBARRAY(A, low, mid,high)

left-sum = - //保存目前为止最大的和

sum = 0             //保存A[i..mid]中所有值的和

for i = mid downto low

  sum = sum + A[i]

   ifsum > left-sum        //每当找到一个子数组A[i..mid]的和大于left-sum

           left-sum = sum     //将left-sum更新为该子数组的和

           max-left = i            //更新变量max-left来记录当前下标i

right-sum = -

sum = 0

for j = mid + 1 to high

  sum = sum + A[j]

   ifsum > right-sum

           right-sum = sum

           max-right = j

return (max-left, max-right, left-sum +right-sum)

 

求解最大子数组问题的分治算法的伪代码如下:

FIND-MAXINUM-SUBARRAY(A, low, high)

if high == low             //子数组只有一个元素的情况

         return(low,high,A[low]) 

else mid =        //划分子数组,计算中点下标mid

         //递归求解左右子数组中的最大子数组

         (left-low,left-high,left-sum)= FIND-MAXINUM-SUBARRAY(A, low, mid)

         (right-low,right-high,right-sum)= FIND-MAXINUM-SUBARRAY(A, mid+1, high)

         //求跨越中点的最大子数组

         (cross-low,cross-high,cross-sum)= FIND-MAX-CROSSING-SUBARRAY(A,low,mid,high)

         //      检测最大子数组位于左子数组,右子数组还是跨越中点的数组

         ifleft-sum >= right-sum and left-sum >= cross-sum

                   return(left-low,left-high,left-sum)

         elseifright-sum >= left-sum and right-sum >= cross-sum

                            return(right-low,right-high,right-sum)

         elsereturn(cross-low,cross-right,cross-sum)

 

对应的C++程序代码如下:

#include <iostream>

 

int Find_MAX_CROSSING_SUBARRAY(int *A,intlow,int mid,int high,int& max_left,int& max_right,int& max_value)

{

         intleft_sum= -1000000;//不可能的最小值

         intsum = 0;

 

         for(inti= mid;i>low;i--)

         {

                   sum= sum+A[i];

                   if(sum>left_sum)

                   {

                            left_sum= sum;

                            max_left=i;

                   }

         }

 

         intright_sum = -1000000;//不可能的最小值

         sum=0;

 

         for(intj=mid+1;j<high;j++)

         {

                   sum= sum+A[j];

                   if(sum>right_sum)

                   {

                            right_sum= sum;

                            max_right=j;

                   }

         }

 

         max_value= left_sum+right_sum;

         return0;

}

 

int Find_MaxiMum_SubArray(int *A,intlow,int high,int& max_left,int& max_right,int& max_value)

{

         if(high==low)

         {

                   max_left  = low;

                   max_right= high;

 

                   max_value= A[low];

         }

         else

         {

                   intmid=(low+high)/2;

 

                   inttmp_left_low;

                   inttmp_left_high;

                   inttmp_left_sum;

 

                   Find_MaxiMum_SubArray(A,low,mid,tmp_left_low,tmp_left_high,tmp_left_sum);

 

                   inttmp_right_low;

                   inttmp_right_high;

                   inttmp_right_sum;

 

                   Find_MaxiMum_SubArray(A,mid+1,high,tmp_right_low,tmp_right_high,tmp_right_sum);

 

                   inttmp_cross_low;

                   inttmp_cross_high;

                   inttmp_cross_sum;

 

                   Find_MAX_CROSSING_SUBARRAY(A,low,mid,high,tmp_cross_low,tmp_cross_high,tmp_cross_sum);

 

                   if((tmp_left_sum>=tmp_right_sum)&&(tmp_left_sum>=tmp_cross_sum))

                   {

                            max_left    = tmp_left_low;

                            max_right   = tmp_left_high;

                            max_value   = tmp_left_sum;

                   }

                   elseif((tmp_right_sum>=tmp_left_sum)&&(tmp_right_sum>=tmp_cross_sum))

                   {

                            max_left    = tmp_right_low;

                            max_right   = tmp_right_high;

                            max_value   = tmp_right_sum;

                   }

                   else

                   {

                            max_left    = tmp_cross_low;

                            max_right   = tmp_cross_high;

                            max_value   = tmp_cross_sum;

                   }

 

         }

 

         return0;

}

 

int B[16] ={13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};

 

int main()

{

 

         std::cout<<std::endl;

 

         intmax_left,max_right,max_value;

         Find_MaxiMum_SubArray(B,0,16,max_left,max_right,max_value);

         std::cout<<max_left<<"\t"<<max_right<<"\t"<<max_value<<std::endl;

         std::cout<<std::endl;

         system("pause");

         return0;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mengrennwpu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值