一、问题描述
题目35. 求一个矩阵中最大的二维矩阵(元素和最大)
如:
1 2 0 3 4
2 3 4 5 1
1 1 5 3 0
中最大的是:
4 5
5 3
要求:(1)写出算法;(2)分析时间复杂度;(3)用C写出关键代码
二、算法分析
解决此问题的方法比较简单:计算所有可能的二维矩阵元素和,选出其中最大的即可。
详细方案:将原矩阵的数据保存在original_array[][]中
1. 通过遍历original_array,将第i列与第i+1列值相加,保存在另一个二维数组new_array的第i列中
2.通过遍历new_array,将第i行与第i+1行值相加,值保存在new_array的第i行中,此时new_array中就保存了所有二维矩阵的元素和
3.遍历new_array,找出最大值,及其对应的行列,就能够得到元素和最大的二维矩阵
此算法时间复杂度和空间复杂度都是O(mn),对于m行n列的原对阵
三、源代码
#include <stdio.h>
#include <stdlib.h>
void display_array(int **array, int row, int col);
void max_2order_sqare(int **array, int row, int col, int max_sub_array[2][2]);
void **malloc_array(int row, int col, int size);
void max_2order_sqare(int **array, int row, int col, int max_sub_array[2][2])
{
int result_row, result_col;//保存最大二维矩阵和的起始行与列
int **new_array = (int **)malloc_array(row,col-1,sizeof(int));//动态申请二维数组,row行col-1列
int i, j;
int max;//保存最大的二维矩阵和
//将原始矩阵的相邻两列值相加:原始矩阵第i列与第i+1列值相加,保存到new_array的第i列中,故new_array的列数少一列
for(i = 0; i < row; i ++)
{
for(j = 0; j < col - 1; j ++)
{
new_array[i][j] = *((int *)array + i*col +j) + *((int *)array + i*col +j + 1);
//二维数组值传递方式为通过二维指针,故不可再通过array[i][j]方式来引用数组中的元素
}
}
//初始化最大子矩阵为原矩阵的[0][0]--[1][1]
max = new_array[0][0] + new_array[1][0];
result_row = 0;
result_col = 0;
/*
**将new_array的相邻两行值相加:new_array的第i行与第i+1行值相加,保存到new_array的第i行中,故new_array的行数也少一列
**经过相邻两行相加处理后,此时的new_array中的元素就是所有二维矩阵元素和,选出其中最大的即为我们想要的结果
*/
for(i = 0; i < row - 1; i ++)
{
for(j = 0; j < col - 1; j ++)
{
new_array[i][j] = new_array[i][j] + new_array[i+1][j];
if(new_array[i][j] > max)
{
max = new_array[i][j];
result_row = i;
result_col = j;
}
}
}
//display_array((int **)new_array,2,4);
display_array((int **)(&new_array[0][0]),row-1,col-1);//输出所有的二维矩阵元素和
//已查找到最大元素和的二维矩阵,将其内容保存到max_sub_array中
max_sub_array[0][0] = *((int *)array + result_row*col + result_col);
max_sub_array[0][1] = *((int *)array + result_row*col + result_col + 1);
max_sub_array[1][0] = *((int *)array + (result_row + 1)* col + result_col);
max_sub_array[1][1] = *((int *)array + (result_row + 1)* col + result_col + 1);
free(new_array);//动态申请二维矩阵后,需释放内存!!!
}
/*
**功能:格式化输出二维数组,重点解决了不需给定二维数组行列固定的问题,行列可以通过参数来指定
**输入:指向指针的指针(由二维数组名通过强制类型转换而来),二维数组的行数和列数
**输出:无
*/
void display_array(int **array, int row, int col)
{
int i, j;
printf("Here is this %d * %d array's numbers:\n",row,col);
for(i = 0; i < row; i ++)
{
for(j = 0; j < col; j ++)
{
printf(" %d",*((int *)array + i*col +j));//此处不能再通过array[i][j]来引用数组中的元素了
}
printf("\n");
}
}
/*
**功能:动态申请二维数组,特点:行数与列数都可变,引用数组元素十分方便,需额外申请col个指针空间
**输入:想要申请的二维数组的行数、列数、单个元素所占的空间大小
**输出:返回一个二维指针,指向动态申请到的空间,可以通过array[i][j]方式来引用数组中的元素
*/
void **malloc_array(int row, int col, int size)
{
int j;
int indexSize;
void **array = NULL;
char *dataStart = NULL;
indexSize = col * sizeof(void *);//需额外申请的内存空间:col个指针内存空间
array = (void **)malloc(indexSize + size * row * col);//实际申请的内存空间大小包含矩阵元素的空间+额外申请的指针空间
dataStart = (char *)array + indexSize;
for(j = 0; j < row; j ++)
{
array[j] = dataStart + size * col * j;
}
return array;
}
int main()
{
int max_sub_array[2][2] = {0}; //2行2列矩阵保存最终结果:具有最大的元素和的二维矩阵
int original_array[3][5] = {{1,2,0,3,4},{2,3,4,5,1},{1,1,5,3,0}};//目标:求解此矩阵的具有最大元素和的二维子矩阵
display_array((int **)original_array,3,5);//调用函数输出原始矩阵
max_2order_sqare((int **)original_array,3,5,max_sub_array);//调用函数处理此问题,将结果保存在矩阵max_sub_array中
display_array((int **)max_sub_array,2,2);//输出最终的查找结果
return 0;
}
/*
动态申请二维数组需要仔细研究
维数不确定的二维数组的值传递问题
*/
四、小结
原以为这个问题很简单,因为算法很简单,但是在编写代码时还是被二维数组和指针给弄的焦头烂额。如果不适用动态创建二维数组,而是用固定维数的二维数组就会比较简单。也知道指针式C语言的难点,可实在没想到二维数组与指针弄到一起,真是伤不起啊。
碰到的主要困难有两个,一个是在写输出二维数组的元素的子函数时,发现在传递二维数组时总需要固定第二维的大小,可是如果这样,那这个子函数的意义就实在太小了。所以希望能够传递一个数组指针进来,然后再传入行和列,这样这个函数就很好用了。从网上找了一篇文章,用二维指针来解决这个问题,自己也不是很懂,姑且先这么用了,以后再深究。另一个问题就是动态创建二维数组了,也是从网上找到的一个方法,原理确实不懂,以后再研究吧。