求矩阵中最大二维矩阵(元素和最大)

一、问题描述

题目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语言的难点,可实在没想到二维数组与指针弄到一起,真是伤不起啊。

碰到的主要困难有两个,一个是在写输出二维数组的元素的子函数时,发现在传递二维数组时总需要固定第二维的大小,可是如果这样,那这个子函数的意义就实在太小了。所以希望能够传递一个数组指针进来,然后再传入行和列,这样这个函数就很好用了。从网上找了一篇文章,用二维指针来解决这个问题,自己也不是很懂,姑且先这么用了,以后再深究。另一个问题就是动态创建二维数组了,也是从网上找到的一个方法,原理确实不懂,以后再研究吧。

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值