数据结构之稀疏矩阵与三元组表示法
稀疏矩阵的概念
在实际应用中,我们经常会遇到一些矩阵,其中大部分元素都是零,只有少量的非零元素。这种矩阵被称为稀疏矩阵。例如,在图像处理、网络分析等领域,稀疏矩阵经常出现。如果使用传统的二维数组来存储稀疏矩阵,会浪费大量的存储空间,因为大部分的数组元素都是零。因此,我们需要一种更高效的存储方法,三元组表示法就是其中之一。
三元组表示法的原理
三元组表示法的核心思想是只存储稀疏矩阵中的非零元素。对于每个非零元素,我们用一个三元组 (i, j, e)
来表示,其中 i
是元素的行号,j
是元素的列号,e
是元素的值。然后,将这些三元组按一定的顺序存储在一个顺序表中,同时记录矩阵的行数、列数和非零元素的个数。这样,我们就可以用一个较小的存储空间来存储稀疏矩阵。
完整代码如下:
#include <stdio.h>
#include <stdlib.h> // 使用标准库的内存分配函数// 定义元素类型为整数
typedef int ElemType;// 定义三元组最大数量
#define MAXSIZE 1000// 三元组结构,用于存储矩阵中非零元素的行、列和值
typedef struct
{int i, j; // i 表示行号,j 表示列号ElemType e; // e 表示元素的值
} Triple;// 三元组顺序表,用于存储稀疏矩阵
typedef struct
{int mu, nu, tu; // mu 为矩阵的行数,nu 为矩阵的列数,tu 为非零元素的个数Triple data[MAXSIZE]; // 存储三元组的静态顺序表
} TSMatrix;// 创建一个三元组表示的稀疏矩阵
void creatTSMatrix(TSMatrix *M, int m, int n)
{int row, col, val;int k = 0;M->mu = m; // 设置矩阵的行数M->nu = n; // 设置矩阵的列数printf("请输入非零元素的行、列、值,以逗号分隔,输入行号为 0 时结束:\n");while (1) {if (scanf("%d,%d,%d", &row, &col, &val) != 3){// 处理输入格式错误printf("输入格式错误,请重新输入!\n");while (getchar() != '\n'); // 清除错误输入continue;}if (row == 0) {break; // 输入行号为 0 时结束输入}if (k >= MAXSIZE - 1){printf("非零元素数量超过最大限制!\n");break;}k++;M->data[k].i = row;M->data[k].j = col;M->data[k].e = val;}M->tu = k; // 记录非零元素的个数
}// 输出三元组稀疏矩阵
void OutputTSMatrix(TSMatrix *M)
{int k;printf("("); // 输出左括号for (k = 1; k < M->tu; k++) {printf("(%d,%d,%d),", M->data[k].i, M->data[k].j, M->data[k].e);}if (M->tu > 0) {printf("(%d,%d,%d)", M->data[k].i, M->data[k].j, M->data[k].e); // 输出最后一个元素,后面无逗号}printf(")"); // 输出右括号printf("\n");
}// 求三元组的转置矩阵三元组
void TSMatrix_Transpose(TSMatrix *M, TSMatrix *T)
{int k, col, i;T->mu = M->nu; // 转置矩阵的行数等于原矩阵的列数T->nu = M->mu; // 转置矩阵的列数等于原矩阵的行数T->tu = M->tu; // 转置矩阵的非零元素个数等于原矩阵的非零元素个数if (T->tu == 0) {printf("矩阵无有效元素,无法转置!\n");return;}k = 1;for (col = 1; col <= M->nu; col++) { for (i = 1; i <= M->tu; i++) // 按列遍历原矩阵{ if (M->data[i].j == col) // 查找所有元素中列号为 col 的元素{T->data[k].i = M->data[i].j; // 把列号变为转置矩阵的行号T->data[k].j = M->data[i].i; // 把行号变为转置矩阵的列号T->data[k].e = M->data[i].e; // 值赋予k++;}}}OutputTSMatrix(T);
}int main()
{TSMatrix *M, *T;int m = 5, n = 4;M = (TSMatrix *)malloc(sizeof(TSMatrix));T = (TSMatrix *)malloc(sizeof(TSMatrix));if (M == NULL || T == NULL) {printf("内存分配失败!\n");return 1;}creatTSMatrix(M, m, n);printf("原矩阵的三元组表示:");OutputTSMatrix(M);printf("转置矩阵的三元组表示:");TSMatrix_Transpose(M, T);free(M); // 释放内存free(T);return 0;
}
数据结构定义
typedef struct {int i, j;ElemType e;
} Triple;typedef struct {int mu, nu, tu;Triple data[MAXSIZE];
} TSMatrix;
这里定义了两个结构体,Triple
结构体用于存储非零元素的三元组,TSMatrix
结构体用于存储稀疏矩阵的基本信息和非零元素的三元组。
创建稀疏矩阵
void creatTSMatrix(TSMatrix *M, int m, int n) {// ...
}
creatTSMatrix
函数用于创建一个三元组表示的稀疏矩阵。通过循环读取用户输入的非零元素的行、列、值,直到输入的行号为 0 时结束。这样,我们就可以将用户输入的稀疏矩阵存储为三元组表示的形式。
输出稀疏矩阵
void OutputTSMatrix(TSMatrix *M) {// ...
}
OutputTSMatrix
函数用于输出三元组稀疏矩阵。按照指定的格式输出所有非零元素的三元组,方便我们查看矩阵的存储情况。
求转置矩阵
void TSMatrix_Transpose(TSMatrix *M, TSMatrix *T) {// ...
}
TSMatrix_Transpose
函数用于求三元组的转置矩阵三元组。通过按列遍历原矩阵,将原矩阵中列号为 col
的元素的列号变为转置矩阵的行号,行号变为转置矩阵的列号,值保持不变。这样,我们就可以得到原矩阵的转置矩阵的三元组表示。
运行:
即原矩阵:0 0 3 转置后:0 0 5
0 0 4 3 0 0
5 0 0 0 4 0
三元组表示法的优缺点
优点
- 节省存储空间:只存储非零元素,避免了大量零元素的存储,节省了存储空间。
- 便于操作:通过三元组表示法,可以方便地进行矩阵的各种操作,如转置、加法等。
缺点
- 插入和删除操作复杂:如果需要插入或删除非零元素,需要对三元组顺序表进行移动和调整,操作比较复杂。
- 不适合随机访问:由于三元组顺序表是按一定顺序存储的,不适合随机访问矩阵中的元素。
总结
稀疏矩阵的三元组表示法是数据结构课程中的一个重要内容,它通过只存储非零元素的方式,有效地节省了存储空间。