数据结构11:二维数组与矩阵乘法

数据结构11:二维数组与矩阵乘法,第1张

摘要: 二维数组在我们学习c语言的时候遇到过,现在我们来试试用数据结构对二维数组进行 *** 作,并且顺便看看c语言是如何给二维数组分配空间的
一.代码块
1)创建

这里分为了静态和动态两个写法,由于静态 *** 作比较简单,我们后续的函数用的动态。

#define ROWS 4
#define COLUMNS 5

/*这种用一个指针指向一个地址表示一个数组的方式我们之前都用过了
,可以体现出动态性,不过要给他动态分配空间,不然就只有一个首地址,
没有结尾了。这里要表示二维数组,就用两个*号就可以了*/ 
typedef struct twoDArray
{
	int rows;
	int columns;
	int **elements;
}*towDArrayPtr;

//这种静态分配不用单独给数组malloc,由于这种比较简单,我们后续的都用的第一种 
typedef struct twoDStaticArray
{
	int rows;
	int columns;
	int elements[ROWS][COLUMNS];
}*twoDStaticArrayPtr;

2)初始化

在开始初始化函数之前,我们要知道一件事情:对于c语言来说,二维数组其实就是一个一维数组,只不过这个一维数组的每个元素又分别是一个一维数组。同理推广到三维数组甚至更高维。其次,c语言的的二维数组是以行序为主序的,即相当于二维数组的每一行单独是一个大的元素,第一行为第一个元素,第二行为第二个元素。

towDArrayPtr twoDArrayInit(int paraRows,int paraColumns)
{
	int i;
	//首先先给结构体 malloc 
	towDArrayPtr resultTwoDArray = (towDArrayPtr)malloc(sizeof(struct twoDArray));
	resultTwoDArray->rows = paraRows;
	resultTwoDArray->columns = paraColumns;
	
	//对于二维数组,先给最外层malloc
	resultTwoDArray->elements = (int**)malloc(paraRows * sizeof(int*));
	
	//然后,在对我们说的每一行的大元素malloc,空间就是每一行元素的个数,即列数
	for(i = 0;i < resultTwoDArray->rows;i ++)
	{
		/*其实,对于二维数组来说,只用一个下标呢就相当于每个元素都是一整行的大元素*/
		resultTwoDArray->elements[i] = (int*)malloc(paraColumns * sizeof(int));
	}
	
	return  resultTwoDArray;
	 
}

3)打印

void outputTwoDArray(towDArrayPtr paraPtr)
{
	int i,j;
	for(i = 0;i < paraPtr->rows;i ++)
	{
		for(j = 0;j < paraPtr->columns;j ++)
		{
			printf("%d ",paraPtr->elements[i][j]);
		} 
		
		printf("\n");
	}
	
	printf("\r\n");
}

4)随机赋值

void randomizeTwoDArray(towDArrayPtr paraPtr, int paraLowerBound, int paraUpperBound)
{
	int i, j;	
	//这里就是一个随机函数,在stdlib头文件里面,给定上下界然后给每个元素赋随机值 
	for (i = 0; i < paraPtr->rows; i ++)
	{
		for (j = 0; j < paraPtr->columns; j ++) 
		{
			paraPtr->elements[i][j] = rand() % (paraUpperBound - paraLowerBound) + paraLowerBound;
		}
	}
}

5)矩阵的乘法

我们要先知道矩阵相乘是怎么算的,然后解读一下这个三重循环

首先,前两重循环就是遍历我们要的矩阵,给每一个矩阵赋值。

第三重循环就是执行我们每一个位置的元素是如何得到的,就是第一个矩阵的第i行每个位置的元素乘以第二个矩阵的第j列每个位置的元素,而k的作用就是遍历第i行或第j列的每个元素。最后把他们加起来。

读者需要自行画个矩阵跟踪一下就会明朗很多

towDArrayPtr matrixMultiply(towDArrayPtr paraPtr1,towDArrayPtr paraPtr2)
{
	int i,j,k,sum;
	if(paraPtr1->columns != paraPtr2->rows)
	{
		printf("这个两个矩阵不能相乘哦0.0\n");
		return ; 
	}
	towDArrayPtr resultPtr;
	resultPtr = twoDArrayInit(paraPtr1->rows,paraPtr2->columns);
	
	for(i = 0;i < paraPtr1->rows;i ++)
		for(j = 0;j < paraPtr2->columns;j ++)
		{
			sum = 0;
			for(k = 0;k < paraPtr1->columns;k ++)
			{
				sum += paraPtr1->elements[i][k] * paraPtr2->elements[k][j]; 
			}
			resultPtr->elements[i][j] = sum; 
		}
		
	return resultPtr; 
}

6)静态版的初始化并且打印其地址

这里简单的给静态数组赋值输出一下,重点是地址的打印让我们直到c语言是怎么看待二维数组的

twoDStaticArrayPtr initTwoDStaticArray()
{
	int i, j;
	twoDStaticArrayPtr resultPtr = (twoDStaticArrayPtr)malloc(sizeof(struct twoDStaticArray));
	resultPtr->rows = ROWS;
	resultPtr->columns = COLUMNS;
	for (i = 0; i < ROWS; i ++)
	{
		for (j = 0; j < COLUMNS; j ++) 
		{
			resultPtr->elements[i][j] = i * 10 + j;
			printf("(%d, %d): %d; \n", i, j, &(resultPtr->elements[i][j]));
		}
	}
	
	return resultPtr;
}

7)测试函数

void twoDArrayTest()
{
	towDArrayPtr tempPtr1, tempPtr2, tempPtr3;
	tempPtr1 = twoDArrayInit(3, 2);
	randomizeTwoDArray(tempPtr1, 1, 5);
	printf("The first matrix:\r\n");
	outputTwoDArray(tempPtr1);

	tempPtr2 = twoDArrayInit(2, 4);
	randomizeTwoDArray(tempPtr2, 4, 9);
	printf("The second matrix:\r\n");
	outputTwoDArray(tempPtr2);

	tempPtr3 = matrixMultiply(tempPtr1, tempPtr2);
	printf("The result:\r\n");
	outputTwoDArray(tempPtr3);
}

三.全部代码

#include 
#include 
#include 

#define ROWS 4
#define COLUMNS 5

/*这种用一个指针指向一个地址表示一个数组的方式我们之前都用过了
,可以体现出动态性,不过要给他动态分配空间,不然就只有一个首地址,
没有结尾了。这里要表示二维数组,就用两个*号就可以了*/ 
typedef struct twoDArray
{
	int rows;
	int columns;
	int **elements;
}*towDArrayPtr;

//这种静态分配不用单独给数组malloc,由于这种比较简单,我们后续的都用的第一种 
typedef struct twoDStaticArray
{
	int rows;
	int columns;
	int elements[ROWS][COLUMNS];
}*twoDStaticArrayPtr;

/*在开始初始化函数之前,我们要知道一件事情:对于c语言来说,二维数组其实就是一个一位数组,
只不过这个一维数组的每个元素又分别是一个一维数组。同理推广到三维数组甚至更高维。其次,c
语言的的二维数组是以行序为主序的,即相当于二维数组的每一行单独是一个大的元素,第一行为第一个
元素,第二行为第二个元素。*/
towDArrayPtr twoDArrayInit(int paraRows,int paraColumns)
{
	int i;
	//首先先给结构体 malloc 
	towDArrayPtr resultTwoDArray = (towDArrayPtr)malloc(sizeof(struct twoDArray));
	resultTwoDArray->rows = paraRows;
	resultTwoDArray->columns = paraColumns;
	
	//对于二维数组,先给最外层malloc
	resultTwoDArray->elements = (int**)malloc(sizeof(int*));
	
	//然后,在对我们说的每一行的大元素malloc,空间就是每一行元素的个数,即列数
	for(i = 0;i < resultTwoDArray->rows;i ++)
	{
		/*其实,对于二维数组来说,只用一个下标呢就相当于每个元素都是一整行的大元素*/
		resultTwoDArray->elements[i] = (int*)malloc(sizeof(int));
	}
	
	return  resultTwoDArray;
	 
}

void randomizeTwoDArray(towDArrayPtr paraPtr, int paraLowerBound, int paraUpperBound)
{
	int i, j;	
	//这里就是一个随机函数,在stdlib头文件里面,给定上下界然后给每个元素赋随机值 
	for (i = 0; i < paraPtr->rows; i ++)
	{
		for (j = 0; j < paraPtr->columns; j ++) 
		{
			paraPtr->elements[i][j] = rand() % (paraUpperBound - paraLowerBound) + paraLowerBound;
		}
	}
}

void outputTwoDArray(towDArrayPtr paraPtr)
{
	int i,j;
	for(i = 0;i < paraPtr->rows;i ++)
	{
		for(j = 0;j < paraPtr->columns;j ++)
		{
			printf("%d ",paraPtr->elements[i][j]);
		} 
		
		printf("\n");
	}
	
	printf("\r\n");
}
/*我们要先知道矩阵相乘是怎么算的,然后解读一下这个三重循环
首先,前两重循环就是遍历我们要的矩阵,给每一个矩阵赋值。
第三重循环就是执行我们每一个位置的元素是如何得到的,就是
第一个矩阵的第i行每个位置的元素乘以第二个矩阵的第j列每个位置
的元素,再把他们加起来。读者需要自行画个矩阵跟踪一下就会明朗很多*/
towDArrayPtr matrixMultiply(towDArrayPtr paraPtr1,towDArrayPtr paraPtr2)
{
	int i,j,k,sum;
	if(paraPtr1->columns != paraPtr2->rows)
	{
		printf("这个两个矩阵不能相乘哦0.0\n");
		return ; 
	}
	towDArrayPtr resultPtr;
	resultPtr = twoDArrayInit(paraPtr1->rows,paraPtr2->columns);
	
	for(i = 0;i < paraPtr1->rows;i ++)
		for(j = 0;j < paraPtr2->columns;j ++)
		{
			sum = 0;
			for(k = 0;k < paraPtr1->columns;k ++)
			{
				sum += paraPtr1->elements[i][k] * paraPtr2->elements[k][j]; 
			}
			resultPtr->elements[i][j] = sum; 
		}
		
	return resultPtr; 
}
/*这里简单的给静态数组赋值输出一下,重点是地址
的打印让我们直到c语言是怎么看待二维数组的*/
twoDStaticArrayPtr initTwoDStaticArray()
{
	int i, j;
	twoDStaticArrayPtr resultPtr = (twoDStaticArrayPtr)malloc(sizeof(struct twoDStaticArray));
	resultPtr->rows = ROWS;
	resultPtr->columns = COLUMNS;
	for (i = 0; i < ROWS; i ++)
	{
		for (j = 0; j < COLUMNS; j ++) 
		{
			resultPtr->elements[i][j] = i * 10 + j;
			printf("(%d, %d): %d; \n", i, j, &(resultPtr->elements[i][j]));
		}
	}
	
	return resultPtr;
}

void twoDArrayTest()
{
	towDArrayPtr tempPtr1, tempPtr2, tempPtr3;
	tempPtr1 = twoDArrayInit(3, 2);
	randomizeTwoDArray(tempPtr1, 1, 5);
	printf("The first matrix:\r\n");
	outputTwoDArray(tempPtr1);

	tempPtr2 = twoDArrayInit(2, 4);
	randomizeTwoDArray(tempPtr2, 4, 9);
	printf("The second matrix:\r\n");
	outputTwoDArray(tempPtr2);

	tempPtr3 = matrixMultiply(tempPtr1, tempPtr2);
	printf("The result:\r\n");
	outputTwoDArray(tempPtr3);
}

int main()
{
	twoDArrayTest();
	twoDStaticArrayPtr tempPtr = initTwoDStaticArray();
}

四.运行结果

矩阵运行结果

The first matrix:
2 4
3 1
2 1

The second matrix:
7 7 6 8
4 4 5 6

The result:
30 30 32 40
25 25 23 30
18 18 17 22

打印地址结果

(0, 0): 11408888;
(0, 1): 11408892;
(0, 2): 11408896;
(0, 3): 11408900;
(0, 4): 11408904;
(1, 0): 11408908;
(1, 1): 11408912;
(1, 2): 11408916;
(1, 3): 11408920;
(1, 4): 11408924;
(2, 0): 11408928;
(2, 1): 11408932;
(2, 2): 11408936;
(2, 3): 11408940;
(2, 4): 11408944;
(3, 0): 11408948;
(3, 1): 11408952;
(3, 2): 11408956;
(3, 3): 11408960;
(3, 4): 11408964;

可以很明显的看到,c语言是以行序为主序的。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/1296067.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-06-10
下一篇2022-06-10

发表评论

登录后才能评论

评论列表(0条)

    保存