## 1484.稀疏矩阵转置
时限:1000ms 内存限制:10000K 总时限:3000ms
描述
输出稀疏矩阵的转置矩阵。(行列均不大于20)
输入
输入两个正整数n和m,为矩阵的行数和列数,然后输入矩阵三元组,(0 0 0)表示结束输入。
输出
转置后的矩阵。
输入样例
4 4
1 1 1
2 1 2
3 2 3
0 0 0
输出样例
1 1 1
1 2 2
2 3 3
# include <iostream>
# include <cstdio>
# include <cmath>
# include <cctype>
# include <vector>
# include <string>
# include <cstring>
# include <algorithm>
using namespace std;
# define Elemtype int
#define MAXSIZE 20//
//typedef struct triple
//{
// //声明一个三元组
// int i;
// int j;
// Elemtype data;
//}triple, * Ptriple;
//typedef struct
//{
// triple data[MAXSIZE];
// int iu, ju, tu;
//}trimatrix, * Ptrimatrix;
typedef struct OLNode
{
//创建节点
//包括一个行号列号和左指针,右指针和数据
int i, j;
Elemtype data;
struct OLNode* right, * down;
} OLNode, * OLink;//创建一个OLink类型的指向这种结构体的指针
typedef struct
{
// 创建十字链表,为了方便直接给它设置为是指针数组
//Rhead是行指针 CHead是列指针
OLink rHead[MAXSIZE] = { NULL };
OLink cHead[MAXSIZE]= {NULL};//先给指针初始化为NULL否则后面处理起来很麻烦
int mu, nu, tu;//行数 列数 和非零元素数量
} CrossList;
void makerow(int i, int j, OLink p, CrossList* Pcs);
void insertl(int a, int b, int c, CrossList* Pcs);
void makecol(int i, int j, OLink p, CrossList* Pcs);
void outputl(CrossList* Pcs);
int main()
{
int x, y, z, u;
cin >> x >> y;
CrossList* Pcs = new CrossList;//生成一个指向十字链表的指针
int a, b, c, d;
while (cin >> a >> b >> c)
{
if (a == 0 && b == 0 && c == 0)break;
insertl(b, a, c, Pcs);
}
outputl(Pcs);
return 0;
}
void insertl(int a, int b, int c, CrossList* Pcs)
{
//实现插入元素 和两个矩阵的相加
OLink P = new OLNode;//先创建一个指向结构体的指针P 对一个节点实体化
P->i = a;//设置好这个节点的参数
P->j = b;
P->data = c;
//下面的步骤主要是为了判断是否在已有元素上加上新值还是新创建一个节点
OLNode *Ka = Pcs->rHead[a];//以行为主要搜索的KEY
int flag = 0;//记住一个flag 指示是否在已有元素上加上新值还是新创建一个节点
while (Ka!= NULL)//当目标行的指针不为空的时候 可以怀疑有元素和已有值重复
{
if (Ka->j == b)//如果这一行上的列号和待插入节点的列号相同 那就给标记++
{
flag++;
break;
}
//边界条件 为了防止在没有right的情况下还向后移动引起段错误
if (Ka->right != NULL)
{
Ka = Ka->right;
}
else
{
break;
}
}
if (flag>0)//在已有元素上加上新值
{
//此时本来Ka指向的位置就是待插入元素的位置 直接在Ka指向的位置上+c
Ka->data += c;
}
else//新创建一个节点
{
//此时梳理行指针和列指针就完成了插入
makerow(a, b, P, Pcs);//行
makecol(a, b, P, Pcs);//列
}
}
void makerow(int a, int b, OLink p, CrossList* Pcs)
{
//先把行作为Key来插入节点
OLink* H = Pcs->rHead;
//H[]:行指针数组
if (H[a] == NULL || H[a]->j > b)
{
//当目标插入位置在第一个或者是在已有元素之前
p->right = H[a];//把目标节点的right赋为行指针的right(NULL)
H[a] = p;
}
else
{
//否则就是在一个已有元素后面
OLNode* q = H[a];//把这一行的指针赋给q 让q往后移动找到目标位置
for (; (q->right) && q->right->j < b; q = q->right);//条件:q->right不为空 且 q->right的列号小于目标节点列号
{
//最后一次循环的时候p->right就等于了q->right即元素被插入了合适的位置
p->right = q->right;
q->right = p;
//满足循环条件退出
}
}
}
void makecol(int a, int b, OLink p, CrossList* Pcs)
{
//列指针
OLink* M = Pcs->cHead;//M[]数组为列指针数组
//OLink* H = Pcs->rHead;//H[]数组为行指针数组
if (M[b] == NULL || M[b]->i > a)
{
//当目标插入位置在第一个或者是在已有元素之前
p->down = M[b];
M[b] = p;
}
else
{
//否则就是在一个已有元素后面
OLNode* q = M[b];//把这一行的指针赋给q 让q往下移动找到目标位置
for (; (q->down) && q->down->i < a; q = q->down)//条件:q->down不为空 且 q->down的行号小于目标节点行号
{
p->down = q->down;
q->down = p;
}
} //完成列插入
}
void outputl(CrossList* Pcs)
{
OLink *Q = Pcs->rHead;//以行为key开始输出 用Q[]指向行指针数组
int u = 0;//u 为计数器
while (u < MAXSIZE)
{
if (Q[u] == NULL)//如果这一行的行指针是空的 那就直接进入下一次循环
{
u++;
continue;
}
else
{
//如果不是空的 就生成一个P指针在这一行上移动输出目标元素
OLNode *P = Q[u];
while (1)//当P的right还不是NULL
{
printf("%d %d %d\n", P->i, P->j, P->data);//先把P指向的元素先输出
if (P->right)P = P->right;//P向右移动
else break;
}
}
u++;
}
}