使用分治策略求解最大子数组,所谓分治策略就是将原问题分解为几个规模较小但类似于原问题的子问题,递归地求解这些子问题,然后再合并这些子问题的解来建立原问题的解。分治策略在每层递归时都有三个步骤:
1、分解原问题为若干子问题,这些子问题是原问题的规模较小的实例。
2、解决子问题,递归的求解各子问题。当递归进入基准情况,则直接求解。
3、合并这些子问题的解成原问题的解
求解最大子数组,可以将其不断分解为更小的两个子数组,直至某个基准情况。则最大子数组要么在左子数组或在右子数组中,要么最大子数组跨越分解点各有一部分在左右子数组中。
C代码如下:
/*使用分治方法求解最大子数组问题,时间复杂度为theta(n*lgn)
* finde_max_crossing_subarray:寻找跨越中点的最大子数组
* @param array 输入数组
* @param low 输入数组的左边界
* @param mid 输入数组的中点
* @param high 输入数组的右边界
* @return 返回最大子数组的边界和最大子数组的和
* find_maximum_subarray:寻找最大子数组
* @param array 输入数组
* @param low 输入数组的左边界
* @param high 输入数组的右边界
* @return 返回最大子数组的边界和最大子数组的和
*/
typedef struct
{
int low; //最大子数组的左边界
int high; //最大子数组的右边界
double sum; //最大子数组值的和
} region_sum;
region_sum find_max_crossing_subarray(double array[], int low, int mid, int high)
{
region_sum result;
double left_sum = array[low];
double right_sum = array[mid + 1];
double sum = 0;
int max_left;
int max_right;
int i, j;
for (i = mid; i >= low; i--)
{
sum += array[i];
if (sum > left_sum)
{
left_sum = sum;
max_left = i;
}
}
sum = 0;
for (j = mid + 1; j <= high; j++)
{
sum += array[j];
if (sum > right_sum)
{
right_sum = sum;
max_right = j;
}
}
result.low = max_left;
result.high = max_right;
result.sum = left_sum + right_sum;
return result;
} // end find_max_crossing_subarray
region_sum find_maximum_subarray(double array[], int low, int high)
{
region_sum result = {low, high, array[low]};
region_sum result_left;
region_sum result_right;
int mid = (low + high) / 2;
if (high == low)
{
return result;
}
else
{
result_left = find_maximum_subarray(array, low, mid);
result_right = find_maximum_subarray(array, mid + 1, high);
result = find_max_crossing_subarray(array, low, mid, high);
if (result_left.sum >= result_right.sum
&& result_left.sum >= result.sum)
{
return result_left;
}
else if (result_right.sum >= result_left.sum
&& result_right.sum >= result.sum)
{
return result_right;
}
else
{
return result;
}
}
} //edn find_maximum_subarray
测试如下:
printf("求解最大子数组测试\n");
double subarray_test[16] = {13, -3, -25, 20, -3, -16, -23, 18,
20, -7, 12, -5, -22, 15, -4, 7};
printf("array=");
for (int i = 0; i < 16; i++)
{
printf("%lf ", subarray_test[i]);
}
region_sum result;
result = find_maximum_subarray(subarray_test, 0, 15);
printf("\nThe maximum subarray index is %d from %d, and the sum is %lf\n",
result.low, result.high, result.sum);
参见《算法导论》