求解数组中的最大子数组问题:分治递归
思想:
把数组分为左右两部分,下标为:left,mid,right,最终的最大子数组的存在形式无非有三种:
*存在于left-mid之间;
*存在于mid两边;
*存在于mid-right之间;
递归问题特征:
*问题解所在的域情况可数;
*同级子问题之间相互独立;
*同级子问题结果作为上一级问题参数;
*问题边界有确定解;
*子问题必须有返回值;
分治算法时间代价分析:
T(n) = 2T(n/2)+Θ(n)
T(n) = Θ(nlgn)
代码:
#include <iostream>
using namespace std;
int* findMaxSubArray_mid(int* arr, int left, int mid, int right); //处理中间体,即递归结构主体
int* findMaxSubArray(int* arr, int left, int right); //寻找最大子数组函数
int main()
{
//例子来源:算法导论(第三版)
int arr[16]={13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7};
//输出最大子数组索引值首位,以及最大子数组和
cout<< findMaxSubArray(arr, 0, 15)[0] <<" "
<< findMaxSubArray(arr, 0, 15)[1] <<" "
<< findMaxSubArray(arr, 0, 15)[2] <<endl;
return 0;
}
int* findMaxSubArray_mid(int *arr, int left, int mid, int right) {
int* subArr = new int[3];
int left_sum = -0x3f3f3f3f; //初始化左右最大之和
int right_sum = -0x3f3f3f3f;
int sum = 0;
int max_left;
int max_right;
for (int i = mid;i >= left;i--) {
sum = sum + arr[i];
if (sum > left_sum)
{
left_sum = sum;
max_left = i;
}
}
sum = 0;
for (int j = mid+1;j <= right;j++) {
sum = sum + arr[j];
if (sum > right_sum) {
right_sum = sum;
max_right = j;
}
}
subArr[0] = max_left;
subArr[1] = max_right;
subArr[2] = left_sum + right_sum;
return subArr;
}
int* findMaxSubArray(int *arr, int left, int right) {
//开辟数组存放左边、右边、中间找到的最大子数组信息,用于比较
int* subArrLeft = new int[3];
int* subArrRight = new int[3];
int* cossingMidSum = new int[3];
int mid;
if (left == right) {
subArrLeft[0] = left;
subArrLeft[1] = right;
subArrLeft[2] = arr[left];
return subArrLeft;
}
else {
mid = (left + right) / 2;
subArrLeft = findMaxSubArray(arr, left, mid);
subArrRight = findMaxSubArray(arr, mid+1, right);
cossingMidSum = findMaxSubArray_mid(arr, left, mid, right);
if (subArrLeft[3] >= subArrRight[3] && subArrLeft[2] >= cossingMidSum[2])
return subArrLeft;
else if (subArrRight[2] >= subArrLeft[2] && subArrRight[2] >= cossingMidSum[2])
return subArrRight;
else
return cossingMidSum;
}
}