题目描述:
解析:
首先是十字链表的建立。十字列表节点包括行号、列号、值、和指向下方和右方的两个指针。然后定义一个十字链表,根据行数m和列数n申请m个行头地址指针rhead,n个列头地址指针chead。
typedef struct Node{//定义十字链表结点
int i,j;
int val;
struct Node *right,*down;
}Node,*Link;
typedef struct{//定义十字链表
Link *rhead,*chead;//定义行和列的头指针地址组
int mu,nu,tu;
}CrossList;
每输入一个节点,检查它所在的行号,其所在行的行头指针为不为空,为空直接连在行头指针后面,不为空就遍历该行的链表,把此节点插入进去。其次检查列号,同理,选择直接连在列头指针后面还是直接插入进去。这样就建立好了十字链表。
建立好两个十字链表之后,同时遍历两个十字链表,根据行号和列号和值得到新的十字链表。
遍历所有的行头指针,如果本行为空说明本行没有链表,直接跳入下一行。如果不为空,说明本行有。遍历改行的链表,得到行号和列号进行比较。不同的话按先后顺序插入,相同的话值相加插入。
重点:
(1)重点是十字链表的建立;
(2)注意遍历十字链表;
代码:
#include<stdio.h>
#include<stdlib.h>
typedef struct OLNode{//定义十字链表结点
int i,j;
int val;
struct OLNode *right,*down;
}OLNode,*OLink;
typedef struct{//定义十字链表
OLink *rhead,*chead;//定义行和列的头指针地址组
int mu,nu,tu;
}CrossList;
void CreatMatrix_OL(CrossList *M, int m, int n, int t){//创建一个m行n列容量为t的十字链表
//初始化M头节点,行、列和容量信息,开辟行列链表头节点空间
M->rhead = M->chead = NULL;
M->mu = m;
M->nu = n;
M->tu = t;
M->rhead = (OLink*)malloc(sizeof(OLink)*(m+1));
M->chead = (OLink*)malloc(sizeof(OLink)*(n+1));
//初始化行列链表头节点
for(int k=1;k<=m;k++){
M->rhead[k] = NULL;
}
for(int k=1;k<=n;k++){
M->chead[k] = NULL;
}
//存储接收的数据
int i,j,v;
for(int k=0;k<t;k++){
int i,j,v;
OLink p,q;
scanf("%d %d %d",&i,&j,&v);
//新建节点储存输入数据,并将其接入十字链表中
p = (OLink)malloc(sizeof(OLNode));
p->i = i;
p->j = j;
p->val = v;
//如果数据所在行的头指针为空,或头指针的列大于数据的列,则数据位置即为头指针
if(M->rhead[i]==NULL || M->rhead[i]->j>j){
M->rhead[i] = p;
}
else{//否则依次查找该元素插入位置
for(q=M->rhead[i];(q->right)&&(q->right->j<j);q=q->right);
p->right = q->right;
q->right = p;
}
p->down = NULL;
//列的操作同行的类似
if(M->chead[j]==NULL || M->chead[j]->i>i){
M->chead[j] = p;
}
else{
for(q=M->chead[j];(q->down)&&(q->down->i<i);q=q->down);
p->down = q->down;
q->down = p;
}
p->right = NULL;
}
}
void Insert(CrossList *M, OLink p){//插入节点
int i=p->i,j=p->j;
if(M->rhead[i]==NULL){//如果该行为空
M->rhead[i] = p;
M->tu++;
}
else{
OLink q=M->rhead[i];
OLink pre = q;//当且仅当插入位置即头节点时有pre=q
while(q&&(q->j<p->j)){//寻找插入位置
pre = q;
q = q->right;
}
if(q&&(q->j==p->j)){//如果插入位置有元素
q->val += p->val;
if(q->val==0){
if(pre==q){
M->rhead[i] = q->right;
}
else{
pre->right = q->right;
}
M->tu--;
}
}
else{//插入位置无元素
if(pre==q){
M->rhead[i] = p;
p->right = q;
}
else{
pre->right = p;
p->right =q;
}
M->tu++;
}
}
if(M->chead[j]==NULL){//列操作与行操作类似
M->chead[j] = p;
}
else{
OLink q=M->chead[j];
OLink pre = q;//当且仅当插入位置即头节点时有pre=q
while(q&&(q->i<p->i)){//寻找插入位置
pre = q;
q = q->down;
}
}
}
void AddElem(CrossList *M, CrossList *N){//将矩阵M加到矩阵N上
OLink p,q;
p = (OLink)malloc(sizeof(OLNode));
for(int k=1;k<=N->mu;k++){
p = N->rhead[k];
while(p){//依次找出N中每个元素插入M中
q = (OLink)malloc(sizeof(OLNode));//不能将p直接插入,会打乱N,应另设一个元素保存数据
q->down = p->down;
q->right = q->right;
q->val = p->val;
q->i = p->i;
q->j = p->j;
Insert(M,q);
p = p->right;
}
}
}
void PrintMatrix_OL(CrossList *M){//按照先行后列依次输出
for(int i=1;i<=M->mu;i++){
OLink p=M->rhead[i];
for(int j=1;j<=M->nu;j++){
if(p&&j==p->j){
printf("%d %d %d\n",p->i,p->j,p->val);
p=p->right;
}
}
}
}
int main(){
int m,n,t1,t2;
scanf("%d %d %d %d",&m,&n,&t1,&t2);
CrossList *M,*N;
M = (CrossList*)malloc(sizeof(CrossList));
N = (CrossList*)malloc(sizeof(CrossList));
CreatMatrix_OL(M,m,n,t1);
CreatMatrix_OL(N,m,n,t2);
AddElem(M,N);
PrintMatrix_OL(M);
return 0;
}