稀疏矩阵的转置和乘法——数据结构课程
稀疏矩阵压缩了储存空间。但在进行运算的时候却没有原矩阵这样方便。
其中,data[0].row data[0].col 储存该矩阵的行和列。
另外,其实在三元数组储存的时候,该程序是默认输入的时候行优先的格式。否则就会出现这种不识别的情况,如果想兼容性强一点,就预先排个序。
在用三元组储存稀疏矩阵的时候,还需要维护:每一行第一个非零元素在三元组中的位置。储存这样的一个信息,就能在访问时,快速定位到到某一行的元素。
#include <iostream> //教学用 2021.10 #include <iomanip> #include <string.h> #include <algorithm> using namespace std; const int MAXSIZE = 100; //定义非零元素的最多个数 const int MAXROW = 10; //定义数组行数的最大值 const int SIZENUM = 10; typedef struct //定义行序优先的顺序表 { typedef struct //定义三元组元素 { int row, col; //矩阵的行号和列号 int value; //矩阵元素值 } term; term data[MAXSIZE+2]; //非0元三元组表 int rpos[MAXROW+1]; //每行第一个非零元素在三元组data中的位置表 } RLSMatrix; //如果输入的格式是行优先 则进行排序处理 bool my_sort(RLSMatrix::term a,RLSMatrix::term b) {return a.row<b.row;} //输入三元组矩阵21 bool InputTSMatrix(RLSMatrix &M) { cout << "输入矩阵的行数、列数和非零元素个数: "; cin >> M.data[0].row >> M.data[0].col >> M.data[0].value; cout << "请输入非零元素对应的行号、列号和相应的元素值: " << endl; for (int i = 1; i <= M.data[0].value; i++) { cin >> M.data[i].row >> M.data[i].col >> M.data[i].value; } return true; } //输出矩阵,按标准格式输出 bool OutputSMatrix(RLSMatrix M) { int i, j, k = 1; for (i = 0; i < M.data[0].row; i++) { for (j = 0; j < M.data[0].col; j++) { if ((M.data[k].row-1) == i && (M.data[k].col-1) == j) { cout << setw(4) << M.data[k].value; k++; } else cout << setw(4) << "0"; }//end_j cout << endl; }//end_i return true; } //稀疏矩阵的快速转置 int FastTranMat() //ok { RLSMatrix M, T; int num[MAXROW+1]; //表示矩阵M中第col列非零元素的个数 int cpot[MAXROW+1]; //表示矩阵M中第col列第一个非0元素在b.data中的位置 int p, q, col, t; InputTSMatrix(M); //输入稀疏矩阵 行列互换 T.data[0].row = M.data[0].col; T.data[0].col = M.data[0].row; T.data[0].value = M.data[0].value;//非零元素的数量 if (T.data[0].value) { for (col = 1; col <= M.data[0].col; col++) //M中各列元素个数初始化 num[col] = 0; for (t = 1; t <= M.data[0].value; t++) { ++num[M.data[t].col ]; //求M中每一列非零元个数 } //求第col列第一个非零元在b.data中的序号 cpot[1] = 1; for (col = 2; col <= M.data[0].col; col++)//对每一列进行扫描 { cpot[col] = cpot[col-1] + num[col-1];//M中第col列第一个非0元素在b.data中的位置 } for (p = 1; p <= M.data[0].value; p++)//由行优先储存到列优先储存的转换 { col = M.data[p].col; //稀疏矩阵M中每个元素对应的列号 q = cpot[col]; //稀疏矩阵M中第一个非零元素位置 T.data[q].row = M.data[p].col; T.data[q].col = M.data[p].row; T.data[q].value = M.data[p].value; ++cpot[col]; }//end_for }//end_if cout << "运用快速算法,输入矩阵的转置为: " << endl; OutputSMatrix(T); return 1; } bool Count(RLSMatrix &M) //计算稀疏矩阵每一行非零元素个数 { int row, p; int num[MAXROW+1]; //预处理 sort(M.data,M.data+M.data[0].value,my_sort) ; for (row = 1; row <= M.data[0].row; row++) { num[row] = 0; //清零 } for (p = 1; p <= M.data[0].value; p++) { ++num[M.data[p].row]; //统计M每一行非零元个数 } M.rpos[1] = 1; //M中每一行非零元素的起始位置 for (row = 2; row <= M.data[0].row; row++) { M.rpos[row] = M.rpos[row-1] + num[row-1]; } return true; } bool MultSMatrix()//两个稀疏矩阵的乘法Q=M*N { RLSMatrix M, N, Q; //构建三个带链接信息的三元组表示的数组 InputTSMatrix(M); //输入矩阵M的三元组数组 InputTSMatrix(N); //输入矩阵N的三元数组 Count(M); //计算矩阵M每行非零数的数量和位置 Count(N);//计算矩阵N if (M.data[0].col != N.data[0].row)//能否进行矩阵乘法 { cout << "Error!"; return false; } //Q的初始化,将结果储存在Q中 Q.data[0].row = M.data[0].row; Q.data[0].col = N.data[0].col; Q.data[0].value = 0; int mrow, nrow, p, q, t, tp, qcol; int ctemp[MAXROW+1]; //辅助数组, //如果Q是非零矩阵 if (M.data[0].value * N.data[0].value) { for (mrow = 1; mrow <= M.data[0].row; mrow++) { //当前行各元素累加器清零 for (int x = 1; x <= N.data[0].col; x++) { ctemp[x] = 0; }//end_x //当前行的首个非零元素在三元组中的位置为此行前所有非0元素加1 Q.rpos[mrow] = Q.data[0].value + 1; if (mrow < M.data[0].row) { tp = M.rpos[mrow+1]; } else //如果当前列为最后一列 tp = M.data[0].value + 1; for (p = M.rpos[mrow]; p < tp; p++) //对当前行的每个非零元素操作 { nrow = M.data[p].col; //在N中找到与M操作元素的c值相等的行值r if (nrow < N.data[0].row) { t = N.rpos[nrow+1]; } else t = N.data[0].value + 1; //对找出的行的每个非零元素进行操作 for (q = N.rpos[nrow]; q < t; q++) { qcol = N.data[q].col; //将乘得到的对应值放在相应元素的累加器里面 ctemp[qcol] += M.data[p].value * N.data[q].value; } }//p_end_for //对已经求出的累加器中的值压缩到Q中 for (qcol = 1; qcol <= Q.data[0].col; qcol++) { if (ctemp[qcol]) { if (++Q.data[0].value > MAXSIZE) { cout << "Error!" << endl; return 0; } Q.data[Q.data[0].value].row = mrow; Q.data[Q.data[0].value].col = qcol; Q.data[Q.data[0].value].value = ctemp[qcol]; } }//qcol_end_for }//arow_end_for }//end_if cout << "两个稀疏矩阵相乘的结果为:\n"; OutputSMatrix(Q); return 1; } int main() { char c; cout << "请选择要进行的操作"; cout << setw(6) << '*' << " 1: 稀疏矩阵的快速转置算法" << endl; cout << setw(6) << '*' << " 2: 稀疏矩阵的乘法的快速算法" << endl; cout << setw(6) << '*' << " 0: 退出程序" << endl; cout.fill(' '); c = getchar(); switch(c) { case '0':break; case '1': FastTranMat();//1: 稀疏矩阵的快速转置算法 break; case '2': MultSMatrix();//2: 稀疏矩阵的乘法的快速算法 break; default: cout << "错误!无此操作" << endl << endl; break; } return 0; }