拓展阅读4——稀疏矩阵的十字链表

合集下载

稀疏矩阵的十字链表加法

稀疏矩阵的十字链表加法

目录前言 (1)正文 (1)1.课程设计的目的和任务 (1)2.课程设计报告的要求 (1)3.课程设计的内容 (2)4.稀疏矩阵的十字链表存储 (2)5.稀疏矩阵的加法思想 (4)6.代码实现 (5)7.算法实现 (5)结论 (8)参考文献 (9)附录 (10)前言采用三元组顺序表存储稀疏矩阵,对于矩阵的加法、乘法等操作,非零元素的插入和删除将会产生大量的数据移动,这时顺序存储方法就十分不便。

稀疏矩阵的链接存储结构称为十字链表,它具备链接存储的特点,因此,在非零元素的个数及位置都会发生变化的情况下,采用链式存储结构表示三元组的线性更为恰当。

正文1.课程设计的目的和任务(1) 使我我们进一步理解和掌握所学的程序的基本结构。

(2) 使我们初步掌握软件开发过程的各个方法和技能。

(3) 使我们参考有关资料,了解更多的程序设计知识。

(4) 使我们能进行一般软件开发,培养我们的能力并提高我们的知识。

2.课程设计报告的要求(1)课程设计目的和任务,为了达到什么要求(2)课程设计报告要求(3)课程设计的内容,都包含了什么东西(4)稀疏矩阵和十字链表的基本概念,稀疏矩阵是怎么用十字链表存储(5)十字链表矩阵的加法(6)代码实现(7)算法检测3.课程设计的内容(1)根据所学知识并自主查找相关资料 (2)进行算法设计与分析(3)代码实现,组建并运行结果查看是否正确 (4)书写课程设计说明书4.稀疏矩阵的十字链表存储稀疏矩阵是零元素居多的矩阵,对于稀疏矩阵,人们无法给出确切的概念,只要非零元素的个数远远小于矩阵元素的总数,就可认为该矩阵是稀疏的。

十字链表有一个头指针hm ,它指向的结点有五个域,如图1所示。

row 域存放总行数m ,col 域存放总列数n ,down 和right 两个指针域空闲不用,next 指针指向第一个行列表头结点。

c o lr o w图1 总表点结点有S 个行列表头结点h[1],h[2],......h[s]。

稀疏矩阵引用十字链表运算

稀疏矩阵引用十字链表运算

稀疏矩阵应用摘要本课程设计主要实现在三元组存储结构与十字链表存储结构下输入稀疏矩阵,并对稀疏矩阵进行转置,相加,相乘操作,最后输出运算后的结果。

在程序设计中,考虑到方法的难易程度,采用了先用三元组实现稀疏矩阵的输入,输出,及其转置,相加,相乘操作的方法,再在十字链表下实现。

程序通过调试运行,结果与预期一样,初步实现了设计目标。

关键词程序设计;稀疏矩阵;三元组;十字链表1 引言•课程设计任务本课程设计主要实现在三元组存储结构与十字链表存储结构下输入稀疏矩阵,并对稀疏矩阵进行转置,相加,相乘操作,最后输出运算后的结果。

稀疏矩阵采用三元组和十字链表表示,并在两种不同的存储结构下,求两个具有相同行列数的稀疏矩阵A和B的相加矩阵C,并输出C;求出A的转置矩阵D,输出D;求两个稀疏矩阵A和B的相乘矩阵E,并输出E。

•课程设计性质数据结构课程设计是重要地实践性教学环节。

在进行了程序设计语言课和《数据结构》课程教学的基础上,设计实现相关的数据结构经典问题,有助于加深对数据结构课程的认识。

本课程设计是数据结构中的一个关于稀疏矩阵的算法的实现,包括在三元组和十字链表下存储稀疏矩阵,并对输入的稀疏矩阵进行转置,相加,相乘等操作,最后把运算结果输出。

此课程设计要求对数组存储结构和链表存储结构非常熟悉,并能熟练使用它们。

1.3课程设计目的其目的是让我们在学习完C、数据结构等课程基础上,掌握多维数组的逻辑结构和存储结构、掌握稀疏矩阵的压缩存储及转置,相加,相乘等基本操作,并用不同的方法输出结果,进一步掌握设计、实现较大系统的完整过程,包括系统分析、编码设计、系统集成、以及调试分析,熟练掌握数据结构的选择、设计、实现以及操作方法,为进一步的应用开发打好基础。

•需求分析2.1设计函数建立稀疏矩阵及初始化值和输出稀疏矩阵的值本模块要求设计函数建立稀疏矩阵并初始化,包括在三元组结构下和十字链表结构下。

首先要定义两种不同的结构体类型,在创建稀疏矩阵时,需要设计两个不同的函数分别在三元组和十字链表下创建稀疏矩阵,在输入出现错误时,能够对错误进行判别处理,初始化稀疏矩阵都为空值,特别注意在十字链表下,对变量进行动态的地址分配。

十字链表存储稀疏矩阵算法

十字链表存储稀疏矩阵算法

十字链表存储稀疏矩阵实现相乘算法#include <stdio.h>#include <stdlib.h>#include <assert.h>#define OK 1#define ERROR 0typedef struct list{int row;int colum;int value;struct list *right;struct list *down;}node,*element;typedef struct link{int row_size;int colum_size;int non_zero_amount;element *rhead;element *chead;}crosslist;int init_matrix(crosslist &one){one.row_size=0;one.colum_size=0;one.non_zero_amount=0;one.rhead=NULL;one.chead=NULL;return OK;}int creat_matrix(crosslist &one){int i;element news,temp;printf("Input the row size of the matrix:");scanf("%d",&one.row_size);printf("Input the colum size of the matrix:"); scanf("%d",&one.colum_size);printf("Input the non zero amount of the matrix:");scanf("%d",&one.non_zero_amount);one.rhead=(element*)malloc(sizeof(element)*(one.row_size+1));assert(one.rhead!=NULL);one.chead=(element*)malloc(sizeof(element)*(one.colum_size+1));assert(one.chead!=NULL);for(i=1;i<=one.row_size;i++)one.rhead[i]=NULL;for(i=1;i<=one.colum_size;i++)one.chead[i]=NULL;printf("/********************************/\n");for(i=1;i<=one.non_zero_amount;i++){news=(element)malloc(sizeof(node));assert(news!=NULL);do{printf("Input the script of the row:");scanf("%d",&news->row);}while(news->row>one.row_size);do{printf("Input the script of the colum:");scanf("%d",&news->colum);}while(news->colum>one.colum_size);printf("Input the value of the node:");scanf("%d",&news->value);if(!one.rhead[news->row]){news->right=NULL;one.rhead[news->row]=news;}else{for(temp=one.rhead[news->row];temp->right!=NULL;temp=temp->right)NULL;news->right=temp->right;temp->right=news;}if(!one.chead[news->colum]){news->down=NULL;one.chead[news->colum]=news;}else{for(temp=one.chead[news->colum];temp->down!=NULL;temp=temp->down)NULL;news->down=temp->down;temp->down=news;}printf("/*******************************/\n");}return OK;}int print_matrix(crosslist &one){element temp;int count;for(count=1;count<=one.row_size;count++){if(!one.rhead[count])continue;else{for(temp=one.rhead[count];temp!=NULL;temp=temp->right){printf("\t%d\t%d\t%d\n",temp->row,temp->colum,temp->value);printf("--------------------------------\n");}}}return OK;}int multi_matrix(crosslist one,crosslist two,crosslist &three){assert(one.colum_size==two.row_size);int i,j;int value;element insert;element pone,ptwo;element prow,pcolum;three.row_size=one.row_size;three.colum_size=two.colum_size;three.non_zero_amount=0;three.rhead=(element*)malloc(sizeof(element)*(three.row_size+1)); assert(three.rhead!=NULL);three.chead=(element*)malloc(sizeof(element)*(three.colum_size+1)); assert(three.chead!=NULL);for(i=1;i<=three.row_size;i++)three.rhead[i]=NULL;for(i=1;i<=three.colum_size;i++)three.chead[i]=NULL;for(i=1;i<=one.row_size;i++){for(j=1;j<=two.colum_size;j++){pone=one.rhead[i];ptwo=two.chead[j];value=0;while(pone!=NULL&&ptwo!=NULL){if(pone->colum==ptwo->row){value+=pone->value*ptwo->value;pone=pone->right;ptwo=ptwo->down;while(pone!=NULL&&ptwo!=NULL){if(pone->colum==ptwo->row){value+=pone->value*ptwo->value;pone=pone->right;ptwo=ptwo->down;}else if(pone->colum>ptwo->row){ptwo=ptwo->down;continue;}else{pone=pone->right;continue;}}if(value==0)break;insert=(element)malloc(sizeof(node));assert(insert!=NULL);insert->row=i;insert->colum=j;insert->value=value;insert->right=NULL;insert->down=NULL;three.non_zero_amount++;if(three.rhead[i]==NULL)three.rhead[i]=prow=insert;else{prow->right=insert;prow=insert;}if(three.chead[j]==NULL)three.chead[j]=pcolum=insert;else{pcolum->down=insert;pcolum=insert;}}else if(pone->colum>ptwo->row){ptwo=ptwo->down;continue;}else{pone=pone->right;continue;}}}}return OK;}int main(void){crosslist one,two,three;char flag;printf("<Creat the first matrix>\n");creat_matrix(one);putchar('\n');printf("Print the first matrix\n");printf("Row\tColum\tValue\n");printf("-----------------------------------\n");print_matrix(one);printf("<Initialization>\n");init_matrix(two);putchar('\n');printf("<Creat the second matrix>\n");creat_matrix(two);putchar('\n');printf("Print the second matrix\n");printf("Row\tColum\tValue\n");printf("-----------------------------------\n");print_matrix(two);printf("Multiply the two matrix\n");init_matrix(three);multi_matrix(one,two,three);printf("The result is below:\n");print_matrix(three);system("pause");}。

十字链表和九宫格算法

十字链表和九宫格算法

十字链表和九宫格算法全文共四篇示例,供读者参考第一篇示例:十字链表和九宫格算法是两种经典的数据结构和算法,在计算机科学领域中具有重要的应用价值。

本文将介绍这两种算法的原理、特点及应用场景,以帮助读者更深入地理解它们。

首先,我们来看看十字链表算法。

十字链表是一种用于表示稀疏矩阵的数据结构,它能够高效地存储和检索稀疏矩阵中的非零元素。

在十字链表中,每个非零元素都会被封装成一个节点,并且节点之间通过指针相互连接,形成一个十字形的链表结构,从而方便对矩阵进行高效的操作。

十字链表算法的核心思想是将原本存储在二维数组中的稀疏矩阵转换成一个链表的形式,从而减少存储空间的消耗和提高检索效率。

通过使用指针连接的方式,可以方便地访问任意一个非零元素,并且在进行矩阵运算时能够大大提高运算效率。

十字链表算法在图论、线性代数和计算机图形学等领域都有广泛的应用。

比如在图论中,可以利用十字链表算法来存储图的邻接矩阵,并且通过遍历链表来查找图中的路径和环路。

在计算机图形学中,可以使用十字链表算法来表示图像的稀疏像素点,从而实现图像的压缩和处理。

接下来,我们来介绍一下九宫格算法。

九宫格算法是一种常用的数独解题算法,它通过递归和回溯的方式来解决数独难题,求解出数独题目的唯一解。

在数独游戏中,每个九宫格都由9个小格子组成,玩家需要填入1-9的数字,使得每一行、每一列和每个九宫格内的数字都不重复。

九宫格算法的核心思想是从数独题目的第一个空格开始逐个填入数字,然后检查当前数字是否符合数独规则。

如果符合规则,则填入下一个空格,依次递归进行。

如果填入的数字不符合规则,则回溯到上一个位置,重新填入其他数字,直到找到正确的解。

九宫格算法在解决数独难题和其他逻辑推理问题上有着重要的应用。

通过使用递归和回溯的方式,可以高效地求解出数独题目的解,并且在解决其他逻辑谜题时也能够发挥重要作用。

总的来说,十字链表算法和九宫格算法都是计算机科学中重要的数据结构和算法,它们在不同领域有着广泛的应用价值。

(原创)数据结构之十字链表总结

(原创)数据结构之十字链表总结

(原创)数据结构之⼗字链表总结7-1 稀疏矩阵(30 分)如果⼀个矩阵中,0元素占据了矩阵的⼤部分,那么这个矩阵称为“稀疏矩阵”。

对于稀疏矩阵,传统的⼆维数组存储⽅式,会使⽤⼤量的内存来存储0,从⽽浪费⼤量内存。

为此,可以⽤三元组的⽅式来存放⼀个稀疏矩阵。

对于⼀个给定的稀疏矩阵,设第r⾏、第c列值为v,且v不等于0,则这个值可以表⽰为 <r,v,c>。

这个表⽰⽅法就称为三元组。

那么,对于⼀个包含N个⾮零元素的稀疏矩阵,就可以⽤⼀个由N个三元组组成的表来存储了。

如:{<1, 1, 9>, <2, 3, 5>, <10, 20, 3>}就表⽰这样⼀个矩阵A:A[1,1]=9,A[2,3]=5,A[10,20]=3。

其余元素为0。

要求查找某个⾮零数据是否在稀疏矩阵中,如果存在则输出其所在的⾏列号,不存在则输出ERROR。

输⼊格式:共有N+2⾏输⼊:第⼀⾏是三个整数m, n, N(N<=500),分别表⽰稀疏矩阵的⾏数、列数和矩阵中⾮零元素的个数,数据之间⽤空格间隔; 随后N⾏,输⼊稀疏矩阵的⾮零元素所在的⾏、列号和⾮零元素的值;最后⼀⾏输⼊要查询的⾮0数据k。

输出格式:如果存在则输出其⾏列号,不存在则输出ERROR。

输⼊样例:在这⾥给出⼀组输⼊。

例如:10 29 32 18 -107 1 988 10 22输出样例:在这⾥给出相应的输出。

例如:8 10解题思路:实际上这道题⽤三元组写轻松解决,但是这⾥想讲的是⼗字链表;⼗字链表的图⼤致如下:那么如何去实现呢;看以下代码:因为下⾯都有注释,这⾥便不赘述了。

1 #include<iostream>2 #include<stdio.h>3using namespace std;45struct OLNod{6int i ; //该⾮零元的⾏下标;7int j ; //该⾮零元的列下标;8int value ; //该⾮零元的数值;9struct OLNod *right ,*down ;//该⾮零元所在的⾏表和列表的后继链域;10 };11struct CrossL{12 OLNod **rhead, **sead;13//⼗字链表的⾏头指针和列头指针;定义为指向指针的指针;14int row; //稀疏矩阵的⾏数;15int col; //稀疏矩阵的列数;16int num; //稀疏矩阵的⾮零个数;17 };1819int InitSMatrix(CrossL *M) //初始化M(CrossL)类型的变量必须初始化;20 {21 (*M).rhead = (*M).sead = NULL;22 (*M).row = (*M).col = (*M).num = 0;23return1;24 }2526int DestroysMatrix(CrossL *M) //销毁稀疏矩阵M;27 {28int i ;29 OLNod *p,*q;30for( i = 1 ; i <= (*M).row;i++)31 {32 p = *((*M).rhead+i); //p指针不断向右移;33while(p!=NULL)34 {35 q = p ;36 p = p ->right;37delete q; //删除q;38 }39 }40delete((*M).rhead); //释放⾏指针空间;41delete((*M).sead); //释放列指针空间;42 (*M).rhead = (*M).sead = NULL; //并将⾏、列头指针置为空;43 (*M).num = (*M).row = (*M).col = 0; //将⾮零元素,⾏数和列数置为0; 44return1;45 }46int CreatSMatrix(CrossL *M)47 {48int i , j , m , n , t;49int value;50 OLNod *p,*q;51if((*M).rhead!=NULL)52 DestroysMatrix(M);53 cin>>m>>n>>t; //输⼊稀疏矩阵的⾏数、列数和⾮零元个数;54 (*M).row = m;55 (*M).col = n ;56 (*M).num = t;57//初始化⾏链表头;58 (*M).rhead = new OLNod*[m+1];//为⾏头指针申请⼀个空间;59if(!(*M).rhead) //如果申请不成功,则退出程序;60 exit(0);61//初始化列链表头;62 (*M).sead = new OLNod*[n+1];//为列表头申请⼀个空间;63if(!(*M).sead) //如果申请不成功,则退出程序;64 exit(0);65for(int k = 1 ; k <= m ; k++)66 {67 (*M).rhead[k] = NULL;//初始化⾏头指针向量;各⾏链表为空链表;68 }69for(int k = 1 ; k <= n ;k++)70 {71 (*M).sead[k] = NULL;//初始化列头指针向量;各列链表为空链表;72 }73for(int k = 0 ; k < t ;k++) //输⼊⾮零元素的信息;74 {75 cin>>i>>j>>value;//输⼊⾮零元的⾏、列、数值;76 p = new OLNod();//为p指针申请⼀个空间;77if(!p) //e如果申请不成功;78 exit(0); //退出程序;79 p->i = i;80 p->j = j;81 p->value = value;82if((*M).rhead[i]==NULL) //如果⾏头指针指向的为空;83 {84//p插在该⾏的第⼀个结点处;85 p->right = (*M).rhead[i];86 (*M).rhead[i] = p;87 }else//如果不指向空88 {89for(q = (*M).rhead[i];q->right; q = q->right);90 p->right = q->right;91 q->right = p;9293 }94if((*M).sead[j]==NULL)//如果列头指针指向的为空;95 {96//p插在该⾏的第⼀个结点处;97 p->down = (*M).sead[j];98 (*M).sead[j] = p;99 }else//如果不指向空100 {101for(q = (*M).sead[j];q->down;q = q->down);102 p->down = q->down;103 q->down = p;104 }105 }106return1;107 }108int PrintSMatrix(CrossL *M)109 {110int flag = 0;111int val ;//要查找的元素的值;112 cin>>val; //输⼊要查找的s值;113 OLNod *p;114for(int i = 1 ; i <= (*M).row ;i++)115 {116for(p = (*M).rhead[i];p;p = p->right) //从⾏头指针开始找,不断向右找117 {118if(p->value==val) //如果能找到119 {120 cout<<p->i<<""<<p->j; //输出⾏下标和列下标121 flag = 1; //标记找到该元素;122 }123 }124 }125126127if(flag==0) //如果找不到128 {129 cout<<"ERROR\n";130 }131132 }133int main()134 {135 CrossL A; //定义⼀个⼗字链表;136 InitSMatrix(&A); //初始化;137 CreatSMatrix(&A); //创建;138 PrintSMatrix(&A); //输出;139 DestroysMatrix(&A); //销毁;140return0;141 }。

十字链表存储稀疏矩阵算法

十字链表存储稀疏矩阵算法

十字链表存储稀疏矩阵实现相乘算法#include <stdio.h>#include <stdlib.h>#include <assert.h>#define OK 1#define ERROR 0typedef struct list{int row;int colum;int value;struct list *right;struct list *down;}node,*element;typedef struct link{int row_size;int colum_size;int non_zero_amount;element *rhead;element *chead;}crosslist;int init_matrix(crosslist &one){one.row_size=0;one.colum_size=0;one.non_zero_amount=0;one.rhead=NULL;one.chead=NULL;return OK;}int creat_matrix(crosslist &one){int i;element news,temp;printf("Input the row size of the matrix:");scanf("%d",&one.row_size);printf("Input the colum size of the matrix:"); scanf("%d",&one.colum_size);printf("Input the non zero amount of the matrix:");scanf("%d",&one.non_zero_amount);one.rhead=(element*)malloc(sizeof(element)*(one.row_size+1));assert(one.rhead!=NULL);one.chead=(element*)malloc(sizeof(element)*(one.colum_size+1));assert(one.chead!=NULL);for(i=1;i<=one.row_size;i++)one.rhead[i]=NULL;for(i=1;i<=one.colum_size;i++)one.chead[i]=NULL;printf("/********************************/\n");for(i=1;i<=one.non_zero_amount;i++){news=(element)malloc(sizeof(node));assert(news!=NULL);do{printf("Input the script of the row:");scanf("%d",&news->row);}while(news->row>one.row_size);do{printf("Input the script of the colum:");scanf("%d",&news->colum);}while(news->colum>one.colum_size);printf("Input the value of the node:");scanf("%d",&news->value);if(!one.rhead[news->row]){news->right=NULL;one.rhead[news->row]=news;}else{for(temp=one.rhead[news->row];temp->right!=NULL;temp=temp->right)NULL;news->right=temp->right;temp->right=news;}if(!one.chead[news->colum]){news->down=NULL;one.chead[news->colum]=news;}else{for(temp=one.chead[news->colum];temp->down!=NULL;temp=temp->down)NULL;news->down=temp->down;temp->down=news;}printf("/*******************************/\n");}return OK;}int print_matrix(crosslist &one){element temp;int count;for(count=1;count<=one.row_size;count++){if(!one.rhead[count])continue;else{for(temp=one.rhead[count];temp!=NULL;temp=temp->right){printf("\t%d\t%d\t%d\n",temp->row,temp->colum,temp->value);printf("--------------------------------\n");}}}return OK;}int multi_matrix(crosslist one,crosslist two,crosslist &three){assert(one.colum_size==two.row_size);int i,j;int value;element insert;element pone,ptwo;element prow,pcolum;three.row_size=one.row_size;three.colum_size=two.colum_size;three.non_zero_amount=0;three.rhead=(element*)malloc(sizeof(element)*(three.row_size+1)); assert(three.rhead!=NULL);three.chead=(element*)malloc(sizeof(element)*(three.colum_size+1)); assert(three.chead!=NULL);for(i=1;i<=three.row_size;i++)three.rhead[i]=NULL;for(i=1;i<=three.colum_size;i++)three.chead[i]=NULL;for(i=1;i<=one.row_size;i++){for(j=1;j<=two.colum_size;j++){pone=one.rhead[i];ptwo=two.chead[j];value=0;while(pone!=NULL&&ptwo!=NULL){if(pone->colum==ptwo->row){value+=pone->value*ptwo->value;pone=pone->right;ptwo=ptwo->down;while(pone!=NULL&&ptwo!=NULL){if(pone->colum==ptwo->row){value+=pone->value*ptwo->value;pone=pone->right;ptwo=ptwo->down;}else if(pone->colum>ptwo->row){ptwo=ptwo->down;continue;}else{pone=pone->right;continue;}}if(value==0)break;insert=(element)malloc(sizeof(node));assert(insert!=NULL);insert->row=i;insert->colum=j;insert->value=value;insert->right=NULL;insert->down=NULL;three.non_zero_amount++;if(three.rhead[i]==NULL)three.rhead[i]=prow=insert;else{prow->right=insert;prow=insert;}if(three.chead[j]==NULL)three.chead[j]=pcolum=insert;else{pcolum->down=insert;pcolum=insert;}}else if(pone->colum>ptwo->row){ptwo=ptwo->down;continue;}else{pone=pone->right;continue;}}}}return OK;}int main(void){crosslist one,two,three;char flag;printf("<Creat the first matrix>\n");creat_matrix(one);putchar('\n');printf("Print the first matrix\n");printf("Row\tColum\tValue\n");printf("-----------------------------------\n");print_matrix(one);printf("<Initialization>\n");init_matrix(two);putchar('\n');printf("<Creat the second matrix>\n");creat_matrix(two);putchar('\n');printf("Print the second matrix\n");printf("Row\tColum\tValue\n");printf("-----------------------------------\n");print_matrix(two);printf("Multiply the two matrix\n");init_matrix(three);multi_matrix(one,two,three);printf("The result is below:\n");print_matrix(three);system("pause");}。

用十字链表和一般方法分别实现稀疏矩阵的乘法和加法资料

用十字链表和一般方法分别实现稀疏矩阵的乘法和加法资料

#include<stdio.h>#include<malloc.h>#define Size 2501# define Size1 51typedef struct{int i;int j;int e;//非零元的值}triple; //定义三元组typedef struct{triple data[Size+1];//矩阵中的元素int rops[Size1+1];// rops[i]为第i行元素中的首非零元在data[]中的序号int mu;//行数int nu;//列数int tu;//非零元数} juzhen;//定义矩阵typedef struct node// 定义十字链表元素{int i,j,e;struct node *right,*down;// 该非零元所在行表和列表的后继元素}node,*link;typedef struct // 定义十字链表对象结构体{link *rhead,*chead;//行和列的头指针int m,n,t;// 系数矩阵的行数,列数,和非零元素个数}crosslist;void createcross(crosslist &M)//建立十字链表{int i,j,e,k;node *p,*q;printf("输入行,列和非零元数,空格隔开:\n");scanf("%d %d %d",&M.m,&M.n,&M.t);M.rhead=(link *)malloc((M.m+1)*sizeof(link));//给行和列的头指针分配内存M.chead=(link *)malloc((M.n+1)*sizeof(link));for(k=1;k<=M.m;k++)//初始化行,列的头指针M.rhead[k]=NULL;for(k=1;k<=M.n;k++)M.chead[k]=NULL;printf("输入非零元的行,列和值,空格隔开:\n");for(k=1;k<=M.t;k++)//输入非零元{scanf("%d %d %d",&i,&j,&e);p=(node *)malloc(sizeof(node));p->i=i;p->j=j;p->e=e;if(M.rhead[i]==NULL||M.rhead[i]->j>j)//插入元素所在行无非零元或首非零元的列标大于插入元素的列标{p->right=M.rhead[i];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;}if(M.chead[j]==NULL||(M.chead[j]->i>i))//插入元素所在列无非零元或首非零元的行标大于插入元素的行标{p->down=M.chead[j];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;}}}void printcross(crosslist A)//输出十字链表{if(A.m==0)printf("十字链表为空!\n");else{printf("十字链表为:\n");int i,j;for(i=1;i<=A.m;i++){link p=A.rhead[i];for(j=1;j<=A.n;j++){if((p)&&(j==p->j)){printf("%5d",p->e);p=p->right; }elseprintf("%5d",0);}printf("\n");}}printf("\n");}crosslist addcross(){printf("十字链表加法:\n");crosslist a,b;// 创建两个十字链表对象,并初始化createcross(a);createcross(b);node *pre,*h[51],*pa,*pb,*q;//定义辅助指针,pa,pb分别为a,b当前比较的元素,pre为pa的前驱元素int i,j,k=0,m,n; //h[j]指向j列的当前插入位置if(a.m!=b.m||a.n!=b.n)printf("格式不对,不能相加!\n");else{for(i=1;i<=a.m;i++){pa=a.rhead[i];pb=b.rhead[i];pre=NULL;for(j=1;j<=a.n;j++)h[j]=NULL;while(pb){p=(node *)malloc(sizeof(node)); // 开辟新节点,存储b中取出的元素p->i=pb->i;p->j=pb->j;p->e=pb->e;if(pa==NULL||pa->j>pb->j)//当a此行已经检查完或者pb因该放在pa前面{if (pre==NULL)a. rhead[p->i]=p;elsepre->right=p;p->right=pa;pre=p;if (h[p->j]==NULL)//当前插入位置下面无非零元//因为是逐行处理,so,h[p->j],依次下移//因此每次都是指向插入的位置{a. chead [p->j]= p;p->down = NULL;}else{p->down = h[p->j]->down;h[p->j]->down = p;}h[p->j]=p;//*******h[p->j]下移指向下次插入的位置pb=pb->right;//pb指向该行下个元素}else if((pa&&pa->j<pb->j))//只要移动pa的指针****先不加||(pb==NULL&&pa){pre = pa;h[pa->j]=pa;//移动h[],使其指向下次插入的位置pa = pa->right;}else if(pa->j==pb->j){pa->e+=pb->e;if(pa->e)//不为零{pre=pa;h[pa->j]=pa;pb=pb->right;//加else//pa->e为零,删除节点{if (pre ==NULL)a.rhead [pa->i]=pa->right;else{pre->right=pa->right;}p=pa;//p指向pa,用来在下面修改列指针pa=pa->right;if (h [p->j]==NULL)a.chead [p->j]=p->down;else{h[p->j]->down=p->down;}free(p);pb=pb->right;}}}}}return a;}void multycross(crosslist &c)//十字链表乘法{node *p,*q,*u,*v,*p1,*p2;crosslist a,b;link *r;int i,j,k,e;printf("十字链表乘法:\n");createcross(a);createcross(b);if(a.n!=b.m)printf("格式错误,不能相乘!\n");else{c.m=a.m;c.n=b.n;c.t=0;c.rhead=(link *)malloc((a.m+1)*sizeof(link));//给行和列的头指针分配内存c.chead=(link *)malloc((b.n+1)*sizeof(link));for(k=1;k<=a.m;k++)//初始化行,列的头指针c.rhead[k]=NULL;for(k=1;k<=b.n;k++)c.chead[k]=NULL;r=(link *)malloc((b.n+1)*sizeof(link));for(i=1;i<=a.m;i++){u=(node *)malloc(sizeof(node));u->e=0;u->i=0;u->j=0;for(k=1;k<=b.n;k++)//初始化r[]r[k]=u;p1=p=a.rhead[i];for(j=1;j<=b.n;j++){p=p1;q=b.chead[j];v=(node *)malloc(sizeof(node));//初始化v,v为将插入c矩阵的元素v->e=0;v->i=i;v->j=j;while(p&&q){if(p->j>q->i)q=q->down;else if(p->j<q->i)p=p->right;else{v->e+=p->e*q->e;p=p->right;q=q->down;}}if(v->e)//如果不为零,则插入c矩阵中{//同建立十字链表if(c.rhead[i]==NULL||c.rhead[i]->j>j)//插入元素所在行无非零元或首非零元的列标大于插入元素的列标{v->right=c.rhead[i];c.rhead[i]=v;}else{for(p2=c.rhead[i];(p2->right)&&(p2->right->j<j);p2=p2->right);//空循环找到第一个列标大于或等于插入元素列标的元素v->right=p2->right;p2->right=v;}if(c.chead[j]==NULL||c.chead[j]->i>i)//插入元素所在列无非零元或首非零元的行标大于插入元素的行标{v->down=c.chead[j];c.chead[j]=v;}else{for(p2=c.chead[j];(p2->down)&&(p2->down->i<i);p2=p2->down);//空循环找到第一个行标大于或等于插入元素行标的元素v->down=p2->down;p2->down=v;}}}}}}void create(juzhen & M) //创建稀疏矩阵{int i,t=0;printf("输入矩阵行数和列数and非零元的个数,以空格隔开:\n");scanf("%d %d %d",&M.mu,&M.nu,&M.tu);printf("输入矩阵非零元的行,列,和数值(中间空格隔开):\n");for(i=1;i<=M.tu;i++)scanf("%d %d %d",&M.data[i].i,&M.data[i].j,&M.data[i].e); //输入三元组的元素for(i=1;i<=Size1;i++)//初始化rops【】M.rops[i]=0;for(i=1,t=1;i<=M.mu;i++)//得到各行第一个元素的序号{M.rops[i]=t;while(M.data[t].i<=i&&t<=M.tu)//遇到i行非零元,则t累加t++;}}void add(juzhen A,juzhen B,juzhen & C)//稀疏矩阵加法{int k=1,temp=0,k1=1, k2=1;//k1,k2,k分别控制A,B,C中非零元的序号变化printf("稀疏矩阵加法:\n");create(A);create(B);if(A.mu!=B.mu||A.nu!=B.nu)printf("格式不对,不能相加!\n");else{while(k1<=A.tu&&k2<=B.tu)//当A,B中的非零元都没用完{if(A.data[k1].i<B.data[k2].i)//A当前k1指向的元素的行标小于列标直接把data 【k1】的值赋给c中data【k】C.data[k++]=A.data[k1++];else if(A.data[k1].i>B.data[k2].i)//同上C.data[k++]=B.data[k2++];else//data[k1],data[k2]行标相同{if(A.data[k1].j>B.data[k2].j)//data[k1]列标大于data[k2]列标,则把data[k2]的值赋给data[k]C.data[k++]=B.data[k2++];else if(A.data[k1].j<B.data[k2].j)//同上C.data[k++]=A.data[k1++];else //行,列标都相同{temp=0;temp=A.data[k1].e+B.data[k2].e;if(temp)//相加后不为零{C.data[k].i=A.data[k1].i;C.data[k].j=A.data[k1].j;C.data[k].e=temp;k++;}k1++;k2++;}}}while(k1<=A.tu)//B中非零元已用完,A中还有非零元C.data[k++]=A.data[k1++];while(k2<=B.tu)//A中非零元已用完,B中还有非零元C.data[k++]=B.data[k2++];C.mu=A.mu;//确定C的行列数和非零元个数C.nu=A.nu;C.tu=k-1;}}void print(juzhen A)//输出稀疏矩阵{printf("\n矩阵为:\n");int i,j,k=1;if(A.mu==0)printf("矩阵为空!\n");else if(A.tu==0)//矩阵元素为空printf("零矩阵!\n");elsefor(i=1;i<=A.mu;i++)//逐行输出{for(j=1;j<=A.nu;j++){if(A.data[k].i==i&&A.data[k].j==j)//行和列分别对应相等则输出相应非零元,否则输出零printf("%5d",A.data[k++].e);elseprintf("%5d",0);}printf("\n");//该行输出结束,空行输出下一行}printf("\n");}void multy(juzhen A,juzhen B,juzhen &C)//稀疏矩阵乘法{int arow,brow,ccol,temp[51],p,q,t,tp,i;//各变量代表含义见下面printf("稀疏矩阵乘法:\n");create(A);create(B);if(A.nu!=B.mu)printf("格式错误,不能相乘!\n");else{C.mu=A.mu;//初始化c的行列及非零元个数C.nu=B.nu;C.tu=0;if(A.nu!=B.mu)printf("A,B格式不对不能相乘!\n");else //{for(arow=1;arow<=A.mu;arow++)//arow为当前A矩阵的行标{for(i=0;i<51;i++)//初始化temptemp[i]=0;if(arow<A.mu)tp=A.rops[arow+1];//tp为arow+1行的首非零元在data【】中的序号else //arow为最后一行tp=A.tu+1;for(p=A.rops[arow];p<tp;p++)//p为A中当前元素在data[]中的序号{brow=A.data[p].j;//brow为与B矩阵中的相应行对应的A中当前元素的列标if(brow<B.mu)t=B.rops[brow+1];//t为brow+1行的首非零元在B中data【】中的序号else //brow大小等于B.mut=B.tu+1;for(q=B.rops[brow];q<t;q++)//q为B中当前元素在B.data[]中的序号{ccol=B.data[q].j;//ccol:data[p]*data[q]所得结果所在的列temp[ccol]+=A.data[p].e*B.data[q].e;//temp【ccol】:相乘所得的C 矩阵中第arow行cool列元素的值}}for(ccol=1;ccol<=B.nu;ccol++)//if(temp[ccol])//temp【ccol】不为零,则把值赋到c中,c.tu加1。

数据结构学习(c)稀疏矩阵(十字链表1)

数据结构学习(c)稀疏矩阵(十字链表1)

数据结构学习(C++)—稀疏矩阵(十字链表【1】)happycock(原作)转自CSDN先说说什么叫稀疏矩阵。

你说,这个问题很简单吗,那你一定不知道中国学术界的嘴皮子仗,对一个字眼的“抠”将会导致两种相反的结论。

这是清华2000年的一道考研题:“表示一个有1000个顶点,1000条边的有向图的邻接矩阵有多少个矩阵元素?是否稀疏矩阵?”如果你是个喜欢研究出题者心理活动的人,你可以看出这里有两个陷阱,就是让明明会的人答错,我不想说出是什么,留给读者思考。

姑且不论清华给的标准答案是什么,那年的参考书是严蔚敏的《数据结构(C语言版)》,书上对于稀疏矩阵的定义是这样的:“非零元较零元少(注:原书下文给出了大致的程度),且分布没有一定规律”,照这个说法,那题的答案应该是不一定是稀疏矩阵,因为可能是特殊矩阵(非零元分布有规律)。

自从2002年换参考书后,很多概念都发生了变化,最明显的是从多少开始计数(0还是1),从而导致的是空树的高度变成了-1,只有一个根节点的树高度是0。

很不幸的是树高的问题几乎年年都考,在你下笔的时候,总是犯点嘀咕,总不是一朝天子一朝臣吧,会不会答案是个兼容版本?然后,新参考书带的习题集里引用了那道考研题,答案是是稀疏矩阵。

你也许会惊讶这年头咸鱼都会游泳了,但这个答案和书并不矛盾,因为在这本黄皮书里,根本就没有什么特殊矩阵,自然就一定是稀疏矩阵了。

其实,这两本书在这个问题上也没什么原则上的问题,C版的是从数据结构实现区分出特殊矩阵和稀疏矩阵,毕竟他们实现起来很不相同;新书一股脑把非零元少的矩阵都当成稀疏矩阵,当你按照这种思路做的时候就会发现,各种结构特殊的非零元很少的矩阵,如果用十字链表来储存的话,比考虑到它的特殊结构得出的特有储存方法,仅仅是浪费了几个表头节点和一些指针域,再有就是一些运算效率的降低。

从我个人角度讲,我更喜欢多一些统一,少一些特别,即使牺牲一点效率;所以在这一点上我赞同新参考书的做法。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

q->down=pa->down;
free (pa);
pa=qa;
} /*if (x==0)*/
else /*第一种情况*/
{
pa->v_next.v=x;
qa=pa;
}
pa=pa->right;
pb=pb->right; } } /*while*/ ca=ca->v_next.next; cb=cb->v_next.next; } while (ca->row==0) return Ha; }
hd[0]=H;
for(i=1; i<=s; i++)
{
p=(MNode*)malloc(sizeof(MNode));
/*申请第 i 个头结点*/
p->row=0; p->col=0;
p->right=p; p->down=p;
hd[i]=p;
hd[i-1]->v_next.next=p;
}
hd[s]->v_next.next=H;
q=hd[i];
while (q->right!=hd[i] && (q->right->col)<j )
/*按列号找位置*/
q=q->right;
p->right=q->right;
/*插入*/
q->right=p;
/*以下是将*p 插入到第 j 列链表中去,且按行号有序*/
q=hd[j];
while (q->down!=hd[j] && (q->down->row)<i ) q=q->down;
if (x==0)
/*第二种情况*/
{
qa->right=pa->right;
./*从行链中删除*/
/*还要从列链中删除,找*pa 的列前驱结点*/
q= Find_JH (Ha,pa->col);
/*从列链表的头结点找起*/
while ( q->down->row < pa->row )
q=q->down;
p->row=pb->row; p->col=pb->col; p->v=pb->v;
p->right=pa;qa->right=p;
/* 新结点插入*pa 的前面*/
pa=p;
/*新结点还要插到列链表的合适位置,先找位置,再插入*/
q=Find_JH(Ha,p->col);
/*从列链表的头结点找起*/
第 i 个行链表中去,同时也按其行号的大小将该结点插入到第 j 个列链表中去。在算法中将
利用一个辅助数组 MNode *hd[s+1],其中 s=max(m , n) , hd [i]指向第 i 行(第 i 列)链表的头
结点。这样做可以在建立链表时随机的访问任何一行(列),为建表带来方便。
【算法 5-4】:
/*十字链表表示的稀疏矩阵的加法*/
{
MNode *p,*q,*pa,*pb,*ca,*cb,*qa;
if (Ha->row!=Hb->row || Ha->col!=Hb->col) return NULL;
ca=Ha->v_next.next;
/*ca 初始指向 A 矩阵中第一行表头结点*/
cb=Hb->v_next.next;
/*cb 初始指向 B 矩阵中第一行表头结点*/
do {
pa=ca->right;
/*pa 指向 A 矩阵当前行中第一个结点*/
qa=ca;
/*qa 是 pa 的前驱*/
pb=cb->right;
/*pb 指向 B 矩阵当前行中第一个结点*/
while (pb->col!=0)
/*当前行没有处理完*/
/*ca 指向 A 中下一行的表头结点*/ /*cb 指向 B 中下一行的表头结点*/
/*当还有未处理完的行则继续*/
为 了 保 持 算 法 的 层 次 , 在 上 面 的 算 法 , 用 到 了 一 个 函 数 Find_JH 。 函 数 Mlink Find_JH(MLink H, int j)的功能是:返回十字链表 H 中第 j 列链表的头结点指针,读者可 自行写出。
/*将头结点们形成循环链表*/
for (k=1;k<=t;k++)
{
scanf (“%d,%d,%d”,&i,&j,&v);
/*输入一个三元组,设值为 inห้องสมุดไป่ตู้*/
p=(MNode*)malloc(sizeof(MNode));
p->row=i ; p->col=j; p->v_next.v=v;
/*以下是将*p 插入到第 i 行链表中去*/
MLink CreatMLink( int m,int n,int t,int s)
/* 建立稀疏矩阵的十字链表*/

MLink H;
MNode *p,*q,*hd[s+1];
int i,j;
Datatype v;
H=(MNode*)malloc(sizeof(MNode));
/*申请总头结点*/
H->row=m; H->col=n;
2.两个十字链表表示的稀疏矩阵的加法**
已知两个稀疏矩阵 A 和 B,分别采用十字链表存储,计算 C=A+B,C 也采用十字链表
方式存储,并且在 A 的基础上形成 C。
由矩阵的加法规则知,只有 A 和 B 行列对应相等,二者才能相加。C 中的非零元素 cij
只可能有3种情况:或者是 aij+bij,或者是 aij (bij=0),或者是 bij (aij=0),因此当 B 加到 A
结点,此时需改变该行链表中前趋结点的 right 域,以及该列链表中前趋结点的 down 域。
(3)若 pa->col < pb->col 且 pa->col≠0(即不是表头结点),则只需要将 pa 指针向右
推进一步,并继续进行比较。
(4)若 pa->col > pb->col 或 pa->col=0(即是表头结点),则需要在矩阵 A 的十字链表
稀疏矩阵的十字链表
1.建立稀疏矩阵 A 的十字链表
首先输入的信息是:m(A 的行数),n(A 的列数),r(非零元的个数),紧跟着输入
的是 r 个形如(i,j,aij)的三元组。
算法的设计思想是:首先建立每行(每列)只有表头结点的空链表,并建立起这些头结
点拉成的循环链表;然后每输入一个三元组(i,j,aij),则将其结点按其列号的大小插入到
while(q->down->row!=0 && q->down->row<p->row)
q=q->down;
p->down=q->down;
/*插在*q 的后面*/
q->down=p;
pb=pb->right;
} /* if */
else
/*第一、二种情况*/
{
x= pa->v_next.v+ pb->v_next.v;
上时,对 A 十字链表的当前结点来说,对应下列四种情况:或者改变结点的值(aij+bij≠0),
或者不变(bij=0),或者插入一个新结点(aij=0),还可能是删除一个结点(aij+bij=0)。
整个运算从矩阵的第一行起逐行进行。对每一行都从行表的头结点出发,分别找到 A
和 B 在该行中的第一个非零元素结点后开始比较,然后按4种不同情况分别处理。设 pa 和
p-> down =q-> down; q-> down =p; }/*for k*/ return H; } /* CreatMLink */
/*按行号找位置*/ /*插入*/
上述算法中,建立头结点循环链表时间复杂度为 O(s),插入每个结点到相应的行表和 列表的时间复杂度是 O(t*s),这是因为每个结点插入时都要在链表中寻找插入位置,所以总 的时间复杂度为 O(t*s)。
pb 分别指向 A 和 B 的十字链表中行号相同的两个结点,4种情况如下:
(1)若 pa->col=pb->col 且 pa->v+pb->v≠0,则只要用 aij+bij 的值改写 pa 所指结点的值
域即可。
(2)若 pa->col=pb->col 且 pa->v+pb->v=0,则需要在矩阵 A 的十字链表中删除 pa 所指
中插入一个 pb 所指结点。
由前面建立十字链表算法知,总表头结点的行列域存放的是矩阵的行和列,而各行(列)
链表的头结点其行列域值为零,当然各非零元素结点的行列域其值不会为零,下面分析的 4
种情况利用了这些信息来判断是否为表头结点。
【算法 5-5】:
MLink AddMat (MLink Ha, MLink Hb)
{
if (pa->col < pb->col && pa->col !=0 )
/*第三种情况*/
{
qa=pa;
pa=pa->right;
}
else
if (pa->col > pb->col || pa->col ==0 )
/*第四种情况*/
相关文档
最新文档