三元组表基础
一般用三元组表来表示稀疏矩阵,定义如下:
typedef struct
{
int row;//行号
int col;//列号
int d;//元素值
}TupNode;
typedef struct
{
int rows;//行数
int cols;//列数
int nums;//非零元素个数
TupNode data[10000];//数据域
}TSMatrix;
``
稀疏矩阵的旋转
稀疏矩阵相加最经典的就是直接让两个矩阵行列对换,但是这种算法时间空间复杂度都比较高,这里记录一次定位快速转置法:
void exchange(TSMatrix A, TSMatrix *B)
{
int num[10000], position[10000];
int col, t, p, q;
if (B->nums > 0)
{
for (col = 1; col <= A.cols; col++)
{
num[col] = 0;
}
for (t = 1; t <= A.nums; t++)
{
num[A.data[t].col]++;
}
position[1] = 1;
for (col = 2; col <= A.cols; col++)
{
position[col] = position[col - 1] + num[col - 1];//核心计算
}
for (p = 1; p <= A.nums; p++)
{
col = A.data[p].col; q = position[col];
B->data[q].row = A.data[p].col;
B->data[q].col = A.data[p].row;
B->data[q].d = A.data[p].d;
position[col]++;//指向下一个列号为col的非零元素在三元组表
B中的存放位置
}
}
}
这个算法核心在要记录两个数据:
1.待转置三元表组A中每一列的非零元素总个数,即转置后矩阵三元表组B的每一行中非零元素总个数
2.待转置矩阵A每一列中第一个非零元素在三元表组B中的位置,即转置后矩阵每一行中第一个非零元素在表B中的位置
为此设立两个数组num[],position[]来记录,如上述代码
主函数如下:
int c, r;
int temp;
cin >> c >> r;//c是行,r是列
TSMatrix A, B;
A.nums = 1; B.nums = 1;
A.rows = c; A.cols = r; B.cols = c; B.rows = r;
for (int i = 1; i <= c; i++)//输入稀疏矩阵并转换成三元组表的形式
{
for (int j = 1; j <= r; j++)
{
cin >> temp;
if (temp != 0)
{
A.data[A.nums].row = i;
A.data[A.nums].col = j;
A.data[A.nums].d = temp;
A.nums++;
}
}
}
A.nums--;
B.nums = A.nums;
exchange(A, &B);
int k =0;
for (int i = 1; i <= r; i++)
{
for (int j = 1; j <= c; j++)
{
if (B.data[k].row == i && B.data[k].col == j)
{
cout << B.data[k].d << " ";
k++;
}
else
{
cout << "0" << " ";
}
}
cout << endl;
}
稀疏矩阵的相加
比起上面的旋转,矩阵相加就容易的多,但是要注意合并完后排序。排序要先按列序排,再按行序排,这样能输出正确的结果。
先附上题目:
【问题描述】
以三元组表存储的稀疏矩阵A、B非零元个数分别为m和n。试编写程序,完成A+B。
【输入形式】
第一排为分别为A、B元素的个数,以下各排分别输入对应的三元组,头m组为A中的元素,接下来为B的元素,同一个矩阵的元素按照行递增排列,第一行规定为1,同一行的元素按照列递增排列,第一列规定为1
【输出形式】
为相应的三元组,以回车分开,如果结果全部为0,则输出 -1 -1 -1
【样例输入】
2 1
1 2 3
1 3 4
1 3 3
【样例输出】
1 2 3
1 3 7
int main()
{
int m, n;
int a, b, c;
TSMatrix A, B;
A.nums = 0; B.nums = 0;
cin >> m >> n;
for (int i = 0; i < m; i++)
{
cin >> a >> b >> c;
A.nums++;//三元组表从1开始存储数据
A.data[A.nums].row = a;
A.data[A.nums].col = b;
A.data[A.nums].d = c;
}
for (int i = 0; i < n; i++)
{
cin >> a >> b >> c;
B.nums++;
B.data[B.nums].row = a;
B.data[B.nums].col = b;
B.data[B.nums].d = c;
}
for (int i = 1; i <= A.nums; i++)
{
for (int j = 1; j <= B.nums; j++)
{
if (A.data[i].row == B.data[j].row && A.data[i].col == B.data[j].col)
{
A.data[i].d = A.data[i].d + B.data[j].d;
for (int r = j; r <= B.nums; r++)//覆盖
{
B.data[r] = B.data[r + 1];
B.nums--;
}
}
}
}
for (int i = 1; i <= B.nums; i++)//连接B表到A表末尾
{
A.nums++;
A.data[A.nums] = B.data[i];
}
for (int j = 1; j <= A.nums; j++)
{
TupNode temp;
for (int i = 1; i <= A.nums-j; i++)
{
if (A.data[i].col > A.data[i + 1].col)
{
temp = A.data[i];
A.data[i] = A.data[i + 1];
A.data[i + 1] = temp;
}
}
}
for (int j = 1; j <= A.nums; j++)
{
TupNode temp;
for (int i = 1; i <= A.nums-j; i++)
{
if (A.data[i].row > A.data[i + 1].row)
{
temp = A.data[i];
A.data[i] = A.data[i + 1];
A.data[i + 1] = temp;
}
}
}
int t = 0;
for (int i = 1; i <= A.nums; i++)
{
if (A.data[i].d!=0)
{
cout << A.data[i].row <<" "<< A.data[i].col<<" " << A.data[i].d << endl;
}
else
{
t++;
}
}
if (t == A.nums)
{
cout << "-1 -1 -1";
}
}
我的思路是先查找两个表中能合并的元素,合并之后就在B表中覆盖掉这个元素。
然后将两个表合并,再排序,最后输出。
这种写法不需要脑子,但是很复杂,要注意等号是否能取到。
用sort函数会简明很多。