此稀疏矩阵我们打算采用十字链表法进行存储。
代码实现及结果测试:
#include<stdio.h>
#include<stdlib.h>
#define null NULL
#define N 4 //矩阵的行数
#define M 7 //矩阵的列数
/*
稀疏矩阵的十字链表法实现方式
*/
//十字链表的元素结点
typedef struct OLNode{
int i,j,value; //i行标 j列标 value元素值
struct OLNode *right,*down; //right是向右的指针 down是向下的指针
}OLNode;
//十字链表行头指针数组,列头指针数组
typedef struct{
struct OLNode **rHead,**lHead; //rHead指向行头指针数组 lHead指向列头指针数组
}CrossList;
//使用十字链表法存储稀疏矩阵
void storage(CrossList *crossList,OLNode *node){
//如果行头指针数组中的头指针为null,证明该行没有一个元素,如果有元素来,直接插入就行
if(*(crossList->rHead+(node->i-1))== null){
*(crossList->rHead+(node->i-1))=node;
}else{
//如果行头指针数组中的头指针不为null,证明该行有元素.我们就要逐一比较,把元素插在合适的位置
OLNode *s = *(crossList->rHead+(node->i-1));
OLNode *p = null;
while(true){
//s==null 表示s走到头了,要退出循环.
if(s==null){
break;
}
if(node->j<s->j){//找到插入位置了,插入到s前面,p之后即可
break;
}
p=s;
s= s->right;
}
//p==null 说明还得插入到该行的第一个位置
if(p == null){
node->right=s;
*(crossList->rHead+(node->i-1))=node;
}else{
//p!=null p指向的是s的前一个元素
node->right=s;
p->right=node;
}
}
//如果列头指针数组中的头指针为null,证明该列没有一个元素,如果有元素来,直接插入就行
if(*(crossList->lHead+(node->j-1))==null){
*(crossList->lHead+(node->j-1))=node;
}else{
//如果列头指针数组中的头指针不为null,证明该列有元素,我们也要逐一比较,把元素插在合适的位置
OLNode *s = *(crossList->lHead+(node->j-1));
OLNode *p = null;
while(true){
if(s==null){
break;
}
if(node->i<s->i){//找到插入位置了,插入到s前面,p之后即可
break;
}
p=s;
s= s->down;
}
//p==null 说明还得插入到该列的第一个位置
if(p == null){
node->down=s;
*(crossList->lHead+(node->j-1))=node;
}else{
//p!=null p指向的是s的前一个元素
node->down=s;
p->down=node;
}
}
}
void initrlHead(CrossList *crossList){
//申请行头指针数组
crossList->rHead = (OLNode **)malloc(sizeof(OLNode *)*N);
//申请列头指针数组
crossList->lHead = (OLNode **)malloc(sizeof(OLNode *)*M);
//行头指针数组元素初始化
for(int i = 0;i<N;i++){
*(crossList->rHead+i)=null;
}
//列头指针数组元素初始化
for(int i = 0;i<M;i++){
*(crossList->lHead+i)=null;
}
}
//打印行
void printHang(CrossList *crossList,int i){
OLNode *head = *(crossList->rHead+(i-1));
while(head != null){
printf("%d ",head->value);
head=head->right;
}
}
//打印列
void printLie(CrossList *crossList , int j){
OLNode * head = *(crossList->lHead+(j-1));
while(head != null){
printf("%d ",head->value);
head=head->down;
}
}
int main(int argc, char *argv[])
{
//用二维数组模拟一个稀疏矩阵
int matrix[N][M]={
{0,0,0,1,0,9,0},
{0,2,0,0,7,0,0},
{0,0,0,0,0,3,0},
{4,0,0,5,0,0,0}
};
CrossList crossList;
initrlHead(&crossList);
//找到二维数组中的非零元素。将非零元素加入到十字链表中。
for(int i = 0;i<N;i++){
for(int j= 0;j<M;j++){
if(matrix[i][j]!=0){
OLNode *s = (OLNode *)malloc(sizeof(OLNode));
s->i=(i+1);
s->j=(j+1);
s->value=matrix[i][j];
s->right=null;
s->down=null;
storage(&crossList,s);
}
}
}
//打印每一行,打印每一列,看一下十字链表有没有成功
printf("第一行元素是 ");
printHang(&crossList,1);
printf("\n");
printf("第二行元素是 ");
printHang(&crossList,2);
printf("\n");
printf("第三行元素是 ");
printHang(&crossList,3);
printf("\n");
printf("第四行元素是 ");
printHang(&crossList,4);
printf("\n");
printf("\n");
printf("\n");
printf("\n");
printf("\n");
printf("第一列元素是 ");
printLie(&crossList,1);
printf("\n");
printf("第二列元素是 ");
printLie(&crossList,2);
printf("\n");
printf("第三列元素是 ");
printLie(&crossList,3);
printf("\n");
printf("第四列元素是 ");
printLie(&crossList,4);
printf("\n");
printf("第五列元素是 ");
printLie(&crossList,5);
printf("\n");
printf("第六列元素是 ");
printLie(&crossList,6);
printf("\n");
printf("第七列元素是 ");
printLie(&crossList,7);
printf("\n");
return 0;
}
从结果图我们能看出,我们的十字链表法存储稀疏矩阵是成功的。
但是我那个storage确定新节点的插入位置代码不简洁。分支很多。
特此借鉴了一下别人的代码,改进了一版storage方法。
改进版storage方法如下:
//改进版的storage方法。
void evolutionStorage(CrossList *crossList,OLNode *node){
//链接到行的指定位置 //以第一个结点为分界点, if是分界点之前找插入位置 else 是分界点之后找插入位置
if(*(crossList->rHead+(node->i-1))==null || node->j<(*(crossList->rHead+(node->i-1)))->j){
node->right=*(crossList->rHead+(node->i-1));
*(crossList->rHead+(node->i-1))= node;
}else{
OLNode *p =*(crossList->rHead+(node->i-1));
//找到插入位置,p之后
for(p;(p->right!=null)&&(p->right->j<node->j);p=p->right);
node->right=p->right;
p->right=node;
}
//链接到列的指定位置
if(*(crossList->lHead+(node->j-1)) == null || node->i<(*(crossList->lHead+(node->j-1)))->i){
node->down = *(crossList->lHead+(node->j-1));
*(crossList->lHead+(node->j-1)) = node;
}else{
OLNode *p =*(crossList->lHead+(node->j-1));
//找到插入位置,p之后
for(p;(p->down!=null)&&(p->down->i<node->i);p=p->down);
node->down=p->down;
p->down=node;
}
}