分治策略求解子数组最大和并输出下标

//FindMaxSubarray.h

//寻找最大子数组的和,分成三种情况来讨论
/*
在数组A[low...high]中,任何连续子数组A[i...j]的位置有三种
一、完全位于数组A[low...mid]中,因此low<=i<=j<=mid
二、完全位于数组A[mid+1...high]中,因此mid<i<=j<=mid
三、跨越了中点,因此low<=i<=mid<j<=high
*/

class FindMaxSubarray
{
public:
	//寻找跨越中点的数组,得到的是crossLow,crossHigh,crossSum
	void findMaxCrossingSubarray(int *,int,int,int);
	//寻找和最大的子数组,得到的是lLow,hHigh,sSum,
	void findMaxSubarray(int *,int,int);

	int getLow(){return lLow;}
	int getHigh(){return hHigh;}
	int getSum(){return sSum;}

private:
	int leftLow,leftHigh,leftSum;
	int rightLow,rightHigh,rightSum;
	int crossLow,crossHigh,crossSum;
	
	int lLow,hHigh,sSum;
};

void FindMaxSubarray::findMaxCrossingSubarray(int *sPtr,int low,int mid,int high)
{
	int sum=0;//临时子数组和,sum不赋值就蛋疼了!!!!!!!!!!
	
	//mid左边的最大和
	int left_sum = sPtr[mid];//最接近mid位置的数作为left_sum

	for(int k=mid;k>=low;k--)
	{
		sum = sum + sPtr[k];
		if(sum>left_sum)//寻找mid左边最大和
		{
			left_sum = sum;
			lLow = k;
		}
	}

	int right_sum = sPtr[mid+1];//最接近mid位置的数作为right_sum
	sum = 0;
	for(int k=mid+1;k<=high;k++)
	{
		sum = sum + sPtr[k];
		if(sum>right_sum)//寻找mid右边最大和
		{
			right_sum = sum;
			hHigh = k;
		}
	}
    
	//得到跨越mid的字串最大和
	sSum = left_sum + right_sum;
}


void FindMaxSubarray::findMaxSubarray(int * sPtr,int low,int high)
{
	if(low == high)//只有一个元素的起情况
	{
		lLow = low;
		hHigh = high;
		sSum = sPtr[low];
	}
	else
	{
		int mid = (low+high)/2;

		findMaxSubarray(sPtr,low,mid);//找出mid左边最大数组和
		leftLow = lLow;
		leftHigh = hHigh;
		leftSum = sSum;

		findMaxSubarray(sPtr,mid+1,high);//找出mid右边最大数组和
		rightLow = lLow;
		rightHigh = hHigh;
		rightSum = sSum;

		findMaxCrossingSubarray(sPtr,low,mid,high);//找出跨越mid的最大数组和
		crossLow = lLow;
		crossHigh = hHigh;
		crossSum = sSum;

		//比较leftSum,rightSum,crossSum的大小来确定sSum
		if((leftSum>=rightSum)&&(leftSum>=crossSum))
		{
			lLow = leftLow;
			hHigh = leftHigh;
			sSum = leftSum;
		}
		else if((rightSum>=leftSum)&&(rightSum>=crossSum))
		{
			lLow = rightLow;
			hHigh = rightHigh;
			sSum = rightSum;
		}
		else
		{
			lLow = crossLow;
			hHigh = crossHigh;
			sSum = crossSum;
		}
 	}
}

//findMaxSubarray.cpp

//寻找最大子数组的和
#include "FindMaxSubarray.h"
#define NUMBER 17
#include <iostream>
using namespace std;

int main()
{
	int testArray[NUMBER+1] = {0,13,-3,-25,-20,-3,-16,23,18,20,-7,12,-5,-22,15,-4,7};
	FindMaxSubarray f1;
	f1.findMaxSubarray(testArray,1,NUMBER);
	cout << "output the array :" << endl;
	for(int i=1;i<=NUMBER;i++)
		cout << " " << testArray[i];
	cout << "\nthe max subarray index is " << f1.getLow() << " to "
		   << f1.getHigh() << endl;
	cout << "the array is :";
	for(int i=f1.getLow();i<=f1.getHigh();i++)
		cout << " " << testArray[i];
	cout << "\nmax subarray is : " << f1.getSum();

	system("pause >> cout");
	return 0;
}


下面的是只需要求出子数组最大和,不要求输出下标的程序

<pre name="code" class="cpp">#include <iostream>
#define NUMBER 17
using namespace std;

int findMaxCrossingSubarray(int *,int,int,int);//跨越mid的最大数组和
int findMaxSubarray(int *,int,int);

int main()
{
	int testArray[NUMBER] = {0,13,-3,-25,-20,-3,-16,23,18,20,-7,12,-5,-22,15,-4,7};
	cout << "output the array :";
	for(int i=1;i<NUMBER;i++)
		cout << " " << testArray[i];
	cout << "\nthe max subarray sum is :" 
		   << findMaxSubarray(testArray,1,NUMBER-1);
	system("pause >> cout");
	return 0;
}

int findMaxCrossingSubarray(int *sPtr,int low,int mid,int high)
{
	int sum=0;

	int left_sum = sPtr[mid];
	for(int i=mid;i>=low;i--)
	{
		sum = sum + sPtr[i];
		if(sum>left_sum)
			left_sum = sum;
	}

	int right_sum = sPtr[mid+1];
	sum = 0;
	for(int k=mid+1;k<=high;k++)
	{
		sum = sum + sPtr[k];
		if(sum>right_sum)
			right_sum = sum;
	}

	sum = left_sum + right_sum;
	return sum;
}

int findMaxSubarray(int *sPtr,int low,int high)
{
	int maxSum;
	if(low == high)
		maxSum = sPtr[low];
	else
	{
		int mid = (low+high)/2;
		int leftSum = findMaxSubarray(sPtr,low,mid);
		int crossSum = findMaxCrossingSubarray(sPtr,low,mid,high);
		int rightSum = findMaxSubarray(sPtr,mid+1,high);

		if(leftSum>=rightSum && leftSum>=crossSum)
			maxSum = leftSum;
		else if(rightSum>=leftSum && rightSum>=crossSum)
			maxSum = rightSum;
		else
			maxSum = crossSum;
	}

	return maxSum;
}


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值