4-1.最大子数组分治法实现

这题的思想是书上的(《算法导论》),代码当然也是按照书上伪码写出的;

《算法导论》中引入这个问题是通过股票的购买与出售,经过问题转换,将前一天的当天的股票差价重新表示出来,即转为了一个最大子数组的问题,具体内容我不多说,转的内容是:

13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7

找到这连续的16个数里面的连续和最大的子数组;

说一下书中的思想吧:

假定我们要寻找子数组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[low..high]的一个最大子数组必然是完全位于A[low..mid]中、完全位于A[mid + 1..high]中或者跨越中点的所有子数组中和最大者。

具体实现代码:

// 最大子数组.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

const int Infinite=-10000;

//寻找跨越最大子数组和
int FindMaxCrossSubarray(int a[],int low,int mid,int high)
{
	int leftsum=Infinite;
	int sum=0;
	for (int i=mid;i>=low;i--)//左半部分
	{
		sum+=a[i];
		if (sum>leftsum)
		{
			leftsum=sum;
		}
	}
	int rightsum=Infinite;
	sum=0;
	for (int i=mid+1;i<=high;i++)//右半部分
	{
		sum+=a[i];
		if (sum>rightsum)
		{
			rightsum=sum;
		}
	}
	return leftsum+rightsum;
}

int FindMaxSubarray(int a[],int low,int high)
{
	int leftsum,rightsum,crosssum;
	if (high==low)//仅有一个元素
	{
		return a[low];
	}
	else
	{
		int mid=(low+high)/2;
		leftsum=FindMaxSubarray(a,low,mid);//前半部分
		rightsum=FindMaxSubarray(a,mid+1,high);//后半部分
		crosssum=FindMaxCrossSubarray(a,low,mid,high);//跨越
		if (leftsum>=rightsum&&leftsum>=crosssum)
		{
			return leftsum;
		}
		else if (rightsum>=leftsum&&rightsum>=crosssum)
		{
			return rightsum;
		}
		else
		{
			return crosssum;
		}
	}
}
int _tmain(int argc, _TCHAR* argv[])
{
	int a[]={13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
	int length=sizeof(a)/sizeof(int);
	printf("%d\n",FindMaxSubarray(a,0,length));
	return 0;
}
时间: 2024-12-28 00:59:33

4-1.最大子数组分治法实现的相关文章

最好理解的快速排序 :实例解析输入数组,排序

1 #include<iostream> 2 using namespace std; 3 void quick_sort(int *num,int l,int r){ 4 int i=l,j=r,mid=num[(l+r)/2]; 5 while(i<=j){ 6 while(num[i]<mid) i++; 7 while(num[j]>mid) j--; 8 if(i<=j){ 9 int temp=num[j]; 10 num[j]=num[i]; 11 num

新手讲排序:归并排序

归并排序给我的感觉:编程一定要认真,不然就算你能想通也要纠缠你很长时间 (1)本质: 1.分解:用二分法,每次将数组分成两个元素数量相同或者差一个(奇数)的子数组,然后递归直到将子数组分成一个一个的元素,实际数组不用分,你直接将它看成已经分好的元素 2.合并:将len=1的数组合并成len=2的数组,合并的时候通过将两个数组的元素按大小插入到临时数组,再将临时数组元素赋予原数组,所以我们得到从len=1到len=len/2的每一个数组都是有序的 (2)例子: 10个元素的例子 1.   10,8

分治法求连续子数组的最大和

思路来自算法导论,将数组平分为左右两个子数组,那么最大子数组可能在左边的子数组中,也有可能在右边的子数组中,还有可能跨过中间的元素,只有这三种情况.对于前两种情况,可以使用递归求解,对于第三种情况,可以做到用线性时间复杂度的函数来求解,详见代码. #include <iostream> #include <map> using namespace std; //the thought of this algrithm is devide-and-couque int int_max

算法实验:分治法合并排序(C++)

这篇文章分两部分来写,第一部分写代码的实现过程,第二部分把实验报告从头到尾呈现出来. 我习惯调试使用的编译器是DEV C++,不是vs系列的,可能头文件上有点区别.但是下面的报告是我放到vs里面测试过的,可以直接用,不影响. 第一部分:(解析) 题目:随机产生一个整型数组,然后用合并排序将该数组做升序排列,要求输出排序前和排序后的数组. 题目分析: 需要随机产生一个整数数组: 采用的算法是合并排序,也就是用归并排序: 输出排序后的数组. 随机产生一个整数数组:这个问题首先想到的是用rand()函

第四章 分治策略 4.1 最大子数组问题 (减治法,别人的,拿来看看)

/** * 获得连续子数组的最大和 * * @author dfeng * */ private static long getMax(long a, long b) { return a > b ? a : b; } /** * 获得连续子数组的最大和 * * @param array * @return 最大和,此处用了Long型是为了表示当参数为null或空时,可以返回null,返回其它任何数字都可能引起歧义. */ public static Long getMax(int[] arra

编程之美——子数组和最大值

解法一:直接求解下标i~j的子数组和最大值:复杂度O(N^2): 代码如下: 1 #include<iostream> 2 using namespace std; 3 const int INF=1000000; 4 5 int maxSum(int arr[],int n); 6 7 int main() 8 { 9 int arr[7]={-2,5,3,-6,4,-8,6}; 10 cout<<maxSum(arr,7)<<endl; 11 return 0; 1

算法设计《分治法》归并排序(三)实例分析之逆序对数

问题定义: 假设A[1...n]是一个有n个不同数的数组.若i<j且A[i]>A[j]则称(A[i], A[j])为数组A的一个逆序对. 例如数组<2, 3, 8, 6, 1>有(2, 1),(3, 1),(8, 6),(8, 1)和(6,1)5个逆序对. 对于这个问题,直观上进行求解的话,使用暴力求解的方式的话,对于每个数num,都遍历数组中num后的所有数的话,则时间复杂度为O(n^2). 实现代码如下: 另一种方式,便是使用分治法,首先将整个数组分成两部分,然后,分别求解两个

求解最大子数组问题 -- 暴力求解 和 分治法求解

/*------------------ 求解最大子数组问题 --------------- 最大子数组,就是求解一个数组的所有元素的各种组合中,和最大的 那个子数组.在这种情况下,如果元素值全部非负,那么最大子数组当然 是所有元素.但是如果有负值的元素存在,那么久需要找到一个由数组中 连续几个元素组成的子数组并且其元素值之和最大. */ #include <iostream> using namespace std; struct ArrayStruct { ArrayStruct(int

分治法解决最大子数组问题

利用分治法解决最大子数组问题(对给定的数组得到该数组中具有最大和的子数组) /* * 对于给定的整数数组A,求出数组中具有最大和的子数组,最大和以及左右下标 * 思路:采用分治的方法,将数组分为两部分,则有最大和的子数组共有三种情况 * 在数组左边,在数组右边,跨越数组中点 */ #include <iostream> using namespace std; //存放左右边界值以及sum值的结构体 /*特别注意结构体的使用!!!!!!!!!!!*/ struct SumBorder { in