C 语言实例 – 矩阵转换:从二维数组到数据重塑
在学习 C 语言的过程中,二维数组是一个绕不开的核心知识点。它不仅是程序处理表格数据的基础,更是许多算法问题的基石。而“矩阵转换”作为二维数组操作中的经典场景,常常出现在图像处理、数学建模、游戏开发等实际应用中。
本文将带你一步步理解 C 语言中如何实现矩阵转换,包括常见的转置、旋转、翻转等操作。通过真实代码示例和详细注释,即使是初学者也能轻松掌握这些技巧。如果你正在准备面试,或者想提升自己的数组操作能力,这篇文章就是为你准备的。
什么是矩阵转换?
在数学中,矩阵是由数字按行和列排列形成的矩形阵列。在编程中,我们通常用二维数组来表示矩阵。例如,一个 3×3 的矩阵可以表示为:
1 2 3
4 5 6
7 8 9
而“矩阵转换”指的是对这个矩阵进行某种规则的重新排列。常见的转换包括:
- 转置:将行变为列,列变为行
- 旋转:顺时针或逆时针旋转 90°、180°
- 翻转:水平或垂直翻转
这些操作在图像处理中非常常见。比如,一张照片旋转 90°,其实就是对像素矩阵进行一次旋转操作。
创建数组与初始化
在 C 语言中,二维数组是连续存储的。我们可以通过静态定义或动态分配来创建。这里以静态方式为例:
#include <stdio.h>
int main() {
// 定义一个 3x3 的二维数组,用于表示矩阵
int matrix[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// 输出原始矩阵
printf("原始矩阵:\n");
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", matrix[i][j]);
}
printf("\n");
}
return 0;
}
代码说明:
int matrix[3][3]:声明一个 3 行 3 列的整型二维数组。- 初始化时使用嵌套的大括号
{},每行对应一个内层数组。 - 外层
for循环控制行,内层控制列,逐个输出元素。 - 每行结束后用
printf("\n")换行,使输出更清晰。
运行结果如下:
原始矩阵:
1 2 3
4 5 6
7 8 9
这个结构就像一张表格,每一行是一个“数据行”,每一列是一个“数据列”。理解这一点,是进行矩阵转换的前提。
实现矩阵转置
转置是将矩阵的行和列互换。例如,原本第 i 行第 j 列的元素,转置后会出现在第 j 行第 i 列。
我们来实现一个转置函数:
#include <stdio.h>
// 转置函数:将原矩阵转置并存入新矩阵
void transpose(int matrix[3][3], int transposed[3][3]) {
// 外层循环:遍历原矩阵的行
for (int i = 0; i < 3; i++) {
// 内层循环:遍历原矩阵的列
for (int j = 0; j < 3; j++) {
// 关键逻辑:将 matrix[i][j] 放到 transposed[j][i]
transposed[j][i] = matrix[i][j];
}
}
}
int main() {
int matrix[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
int transposed[3][3]; // 存放转置结果
// 调用转置函数
transpose(matrix, transposed);
// 输出转置后的矩阵
printf("转置后的矩阵:\n");
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", transposed[i][j]);
}
printf("\n");
}
return 0;
}
代码说明:
transpose函数接收两个参数:原矩阵和目标矩阵。transposed[j][i] = matrix[i][j]是转置的核心逻辑——交换行列索引。- 注意:目标矩阵必须有足够空间,否则会越界。
输出结果为:
转置后的矩阵:
1 4 7
2 5 8
3 6 9
你可以想象成:把一张表格从“横着看”变成“竖着看”,每一行变成一列。
实现矩阵旋转(顺时针 90°)
顺时针旋转 90° 是一个更复杂的操作。我们可以借助转置 + 翻转来实现。
步骤如下:
- 先对矩阵进行转置
- 再对每一行进行水平翻转(左右互换)
#include <stdio.h>
// 水平翻转:每一行左右对调
void flip_horizontal(int matrix[3][3]) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3 / 2; j++) {
// 交换第 j 列与第 (2-j) 列的元素
int temp = matrix[i][j];
matrix[i][j] = matrix[i][2 - j];
matrix[i][2 - j] = temp;
}
}
}
// 旋转 90 度顺时针:先转置,再水平翻转
void rotate_90_clockwise(int matrix[3][3]) {
// 步骤1:转置
for (int i = 0; i < 3; i++) {
for (int j = i + 1; j < 3; j++) {
// 只处理上三角,避免重复交换
int temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
}
}
// 步骤2:水平翻转
flip_horizontal(matrix);
}
int main() {
int matrix[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
printf("旋转前:\n");
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", matrix[i][j]);
}
printf("\n");
}
rotate_90_clockwise(matrix);
printf("旋转 90 度顺时针后:\n");
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", matrix[i][j]);
}
printf("\n");
}
return 0;
}
代码说明:
rotate_90_clockwise函数中,第一层循环只处理j > i的部分,避免重复交换。flip_horizontal通过循环前半列与后半列交换实现。- 旋转后结果为:
旋转 90 度顺时针后:
7 4 1
8 5 2
9 6 3
这个操作就像把一张纸从桌面旋转 90°,右上角变成左上角。
实现矩阵翻转(垂直翻转)
垂直翻转是指上下对调。第 0 行和最后一行交换,第 1 行和倒数第二行交换。
#include <stdio.h>
// 垂直翻转:上下对调
void flip_vertical(int matrix[3][3]) {
for (int i = 0; i < 3 / 2; i++) {
for (int j = 0; j < 3; j++) {
// 交换第 i 行与第 (2-i) 行
int temp = matrix[i][j];
matrix[i][j] = matrix[2 - i][j];
matrix[2 - i][j] = temp;
}
}
}
int main() {
int matrix[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
printf("翻转前:\n");
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", matrix[i][j]);
}
printf("\n");
}
flip_vertical(matrix);
printf("垂直翻转后:\n");
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", matrix[i][j]);
}
printf("\n");
}
return 0;
}
输出结果为:
垂直翻转后:
7 8 9
4 5 6
1 2 3
这就像把一张照片从上往下倒过来。
通用化处理:动态矩阵转换
上面的例子都是固定大小的 3×3 矩阵。但在实际应用中,矩阵大小可能不确定。我们可以使用动态内存分配来支持任意大小。
#include <stdio.h>
#include <stdlib.h>
// 动态分配二维数组
int** create_matrix(int rows, int cols) {
int** matrix = (int**)malloc(rows * sizeof(int*));
for (int i = 0; i < rows; i++) {
matrix[i] = (int*)malloc(cols * sizeof(int));
}
return matrix;
}
// 释放动态矩阵内存
void free_matrix(int** matrix, int rows) {
for (int i = 0; i < rows; i++) {
free(matrix[i]);
}
free(matrix);
}
// 通用转置函数(支持任意大小)
void transpose_dynamic(int** matrix, int** transposed, int rows, int cols) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
transposed[j][i] = matrix[i][j];
}
}
}
int main() {
int rows = 3, cols = 4;
// 创建原矩阵和转置矩阵
int** matrix = create_matrix(rows, cols);
int** transposed = create_matrix(cols, rows);
// 初始化原矩阵
int value = 1;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] = value++;
}
}
// 执行转置
transpose_dynamic(matrix, transposed, rows, cols);
// 输出结果
printf("原始 %d x %d 矩阵:\n", rows, cols);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("%2d ", matrix[i][j]);
}
printf("\n");
}
printf("\n转置后 %d x %d 矩阵:\n", cols, rows);
for (int i = 0; i < cols; i++) {
for (int j = 0; j < rows; j++) {
printf("%2d ", transposed[i][j]);
}
printf("\n");
}
// 释放内存
free_matrix(matrix, rows);
free_matrix(transposed, cols);
return 0;
}
关键点:
- 使用
malloc为每行分配内存,形成“行指针数组”。 - 转置时需注意行列顺序。
- 最后必须调用
free释放内存,避免内存泄漏。
小结
通过本文,我们系统地学习了 C 语言中常见的矩阵转换操作:转置、旋转、翻转,并提供了完整的代码示例和详细注释。这些操作虽然看似简单,却是许多高级算法(如图像处理、矩阵运算、游戏逻辑)的基础。
C 语言实例 – 矩阵转换 不仅帮助你掌握二维数组的使用,也培养了你对数据结构的敏感度。记住,编程不是死记硬背,而是理解“为什么这样写”。每一次循环、每一次索引交换,背后都有其逻辑意义。
希望你能动手运行这些代码,尝试修改矩阵大小,甚至加入输入功能,让程序更灵活。编程之路,始于实践。继续加油!