数组与广义表的算法的实验报告
《数据结构》教案 第四章 数组和广义表

ch4 数组和广义表本实习单元是作为从线性结构到非线性结构的过渡来安排的。
数组和广义表可以看成其元素本身也是自身结构( 递归结构 ) 的线性表。
广义表本质上是一种层次结构 , 自顶向下识别并建立一个广义表的操作,可视为某种树的遍历操作:遍历逻辑的〈或符号形式的)结构,访问动作是建立一个结点。
稀疏矩阵的十字链表存储结构也是图的一种存储结构。
由此可见,这个实习单元的训练具有承上启下的作用。
希望读者能深入研究数组的存储表示和实现技术,熟悉广义表的存储结构的特性。
编程技术训练要点:稀疏矩阵的表示方法及其运算的实现(4.1〉;共享数据的存储表示方法(4.2);形式系统的自底向上和自顶向下识别技术(4.3 〉; 递归算法的设计方法(4.3);表达式求值技术 (4.4) 。
1. 稀疏矩阵运算器【问题描述】稀疏矩阵是指那些多数元素为零的矩阵。
利用 " 稀疏 " 特点进行存储和计算可以大大节省存储空间 , 提高计算效率。
实现一个能进行稀疏矩阵基本运算的运算器。
【基本要求】以"带行逻辑链接信息"的三元组顺序表表示稀疏矩阵,实现两个矩阵相加、相减和相乘的运算。
稀疏矩阵的输入形式采用三元组表示 , 而运算结果的矩阵则以通常的阵列形式列出。
【测试数据】【实现提示】1. 首先应输入矩阵的行数和列数 , 并判别给出的两个矩阵的行、列数对于所要求作的运算是否相匹配。
可设矩阵的行数和列数均不超过 20 。
2. 程序可以对三元组的输入顺序加以限制 , 例如 , 按行优先。
注意研究教科书 5.3.2节中的算法 , 以便提高计算效率。
3. 在用三元组表示稀疏矩阵时 , 相加或相减所得结果矩阵应该另生成 , 乘积矩阵也可用二维数组存放。
【选作内容】1. 按教科书 5.3.2 节中的描述方法 , 以十字链表表示稀疏矩阵。
2. 增添矩阵求逆的运算 , 包括不可求逆的情况。
在求逆之前 , 先将稀疏矩阵的内部表示改为十字链表。
广义表实验报告

⼴义表实验报告抽象数据类型的实现1.实验概要实验项⽬名称: 抽象数据类型的实现实验项⽬性质: 设计性实验所属课程名称: 数据结构实验计划学时: 62.实验⽬的对某个具体的抽象数据类型,运⽤课程所学的知识和⽅法,设计合理的数据结构,并在此基础上实现该抽象数据类型的全部基本操作。
通过本设计性实验,检验所学知识和能⼒,发现学习中存在的问题。
进⽽达到熟练地运⽤本课程中的基础知识及技术的⽬的。
3.编译软件Microsoft Visual C++6.04.抽象数据类型定义以及各基本操作的简要描述ADT GList{数据对象:D={i=1,2,...,n>=0;ei (-AtomSet或ei (-GList,AtomSet为某个数据对象} 数据关系:R1={|ei-1,ei (-D,2=基本操作:InitGlist(&L);操作结果:创建空的⼴义表LCreateGList(&L,S);初始条件:S是⼴义表的书写形式串操作结果:由S创建⼴义表LDestroyGlist(&L);初始条件:⼴义表L存在操作结果:销毁⼴义表LCopyGlist(&T,L);初始条件:⼴义表L存在操作结果:由⼴义表L复制得到⼴义表TGListLength(L);初始条件:⼴义表L存在操作结果:求⼴义表L的长度,即元素个数GListDepth(L);初始条件:⼴义表L存在初始条件:⼴义表L存在操作结果:判断⼴义表L是否为空GetHead(L);初始条件:⼴义表L存在操作结果:取⼴义表L的头GList GetTail(L)初始条件:⼴义表L存在操作结果: 取⼴义表L的尾InsertFirst_GL(&L,e)初始条件:⼴义表L存在操作结果:插⼊元素e作为⼴义表L的第⼀元素DeleteFirst_GL(GList &L,&e)初始条件:⼴义表L存在操作结果:删除⼴义表L的第⼀元素,并⽤e返回其值Traverse_GL(GList L,void(*v)(AtomType))初始条件:⼴义表L存在操作结果:遍历⼴义表L,⽤函数Visit处理每个元素} ADT GList5.⼴义表的存储结构-------⼴义表的扩展线性链表存储表⽰------typedef enum{ATOM,LIST}ElemTag; // ATOM==0:原⼦,LIST==1:⼦表typedef struct GLNode{ElemTag tag; // 公共部分,⽤于区分原⼦结点和表结点union // 原⼦结点和表结点的联合部分{AtomType atom; // 原⼦结点的值域struct GLNode *hp; // 表结点的表头指针}a;struct GLNode *tp; // 相当于线性链表的next,指向下⼀个元素结点 }*GList,GLNode;6.主函数及部分函数流程图主函数流程图:由S创建⼴义表L流程图:销毁⼴义表L流程图:求⼴义表L深度流程图:⼴义表L长度流程图:遍历⼴义表L流程图:7.程序清单#include /头⽂件a.h/#include#include#include#include#define TRUE 1 / 函数结果状态代码/ #define FALSE 0#define OK 1#define ERROR 0#define OVERFLOW -2typedef char AtomType;typedef int Status;typedef struct / 串的堆分配存储/{char *ch;int length;}HString;typedef enum{ATOM,LIST}ElemTag; /⼴义表的扩展线性链表存储表⽰/ typedef struct GLNode {ElemTag tag;union{AtomType atom;struct GLNode *tp;}*GList,GLNode;void InitString(HString *T); /函数声明/int StrCompare(HString S,HString T);int StrLength(HString S);Status StrAssign(HString *T,char *chars);Status StrCopy(HString *T,HString S);Status StrEmpty(HString S);Status ClearString(HString *S);Status SubString(HString *Sub, HString S,int pos,int len); Status sever(HString *str,HString *hstr);GList GetHead(GList L);GList GetTail(GList L);void visit(AtomType e);void Traverse_GL(GList L,void(*v)(AtomType));int GListLength(GList L);int GListDepth(GList L);Status InitGList(GList *L);Status CreateGList(GList *L,HString S);Status DestroyGList(GList *L);Status CopyGList(GList *T,GList L);Status GListEmpty(GList L);Status InsertFirst_GL(GList *L,GList e);Status DeleteFirst_GL(GList *L,GList *e);Status StrAssign(HString *T,char *chars) /串的操作/ { /⽣成⼀个其值等于串常量chars的串T / int i,j;if((*T).ch)free((*T).ch); /释放T原有空间/i=strlen(chars);if(!i){(*T).ch=NULL;(*T).length=0;{(*T).ch=(char*)malloc(i*sizeof(char)); /分配串空间/ if(!(*T).ch)exit(OVERFLOW);for(j=0;j(*T).ch[j]=chars[j];(*T).length=i;}return OK;}Status StrCopy(HString *T,HString S){ /由串S复制得串T /int i;if((*T).ch)free((*T).ch); /释放T原有空间/(*T).ch=(char*)malloc(S.length*sizeof(char));if(!(*T).ch) /分配串空间失败/exit(OVERFLOW);for(i=0;i(*T).ch[i]=S.ch[i];(*T).length=S.length;return OK;}Status StrEmpty(HString S){ /若S为空串,则返回TRUE,否则返回FALSE /if(S.length==0&&S.ch==NULL)return TRUE;elsereturn FALSE;}int StrCompare(HString S,HString T){ /若S>T,则返回值>0;若S=T,则返回值=0;若Sfor(i=0;ireturn S.length-T.length;}int StrLength(HString S){ /返回S的元素个数,称为串的长度/return S.length;}Status ClearString(HString *S){ /清空串/if((*S).ch){free((*S).ch);(*S).ch=NULL;}(*S).length=0;return OK;}Status SubString(HString *Sub, HString S,int pos,int len) { /⽤Sub返回串S的第pos个字符起长度为len的⼦串/ int i; if(pos<1||pos>S.length||len<0||len>S.length-pos+1) return ERROR;if((*Sub).ch)free((*Sub).ch);if(!len) /空⼦串/{(*Sub).ch=NULL;(*Sub).length=0;}else / 完整⼦串/{(*Sub).ch=(char*)malloc(len*sizeof(char));if(!(*Sub).ch)exit(OVERFLOW);for(i=0;i<=len-1;i++)return OK;}void InitString(HString *T){ /产⽣空串/(*T).length=0;(*T).ch=NULL;}Status sever(HString *str,HString *hstr){ /将⾮空串str分割成两部分:hstr为第⼀个','之前的⼦串,str为之后的⼦串/ int n,i=1,k=0; HString ch,c1,c2,c3;InitString(&ch);InitString(&c1);InitString(&c2);InitString(&c3);StrAssign(&c1,",");StrAssign(&c2,"(");StrAssign(&c3,")");n=StrLength(*str);do{SubString(&ch,*str,i,1);if(!StrCompare(ch,c2))++k;else if(!StrCompare(ch,c3))--k;++i;}while(i<=n&&StrCompare(ch,c1)||k!=0);if(i<=n){StrCopy(&ch,*str);SubString(hstr,ch,1,i-2);SubString(str,ch,i,n-i+1);StrCopy(hstr,*str);ClearString(str);}return OK;}Status InitGList(GList *L) /⼴义表的操作/ { /创建空的⼴义表/*L=NULL;return OK;}Status CreateGList(GList *L,HString S) { /由S创建⼴义表/HString emp,sub,hsub;GList p;InitString(&emp);InitString(&sub);InitString(&hsub);StrAssign(&emp,"()");*L=(GList)malloc(sizeof(GLNode));if(!*L)exit(OVERFLOW);if(!StrCompare(S,emp)) /创建空表/{(*L)->tag=LIST;(*L)->a.hp=NULL;(*L)->tp=NULL;}else if(StrLength(S)==1) /创建单原⼦⼴义表/ {(*L)->tag=ATOM;(*L)->a.atom=S.ch[0];(*L)->tp=NULL;(*L)->tag=LIST;(*L)->tp=NULL;SubString(&sub,S,2,StrLength(S)-2); /脱外层括号/sever(&sub,&hsub); / 从sub中分离出表头串hsub / CreateGList(&(*L)->a.hp,hsub); p=(*L)->a.hp;while(!StrEmpty(sub)) /表尾不空,则重复建n个⼦表/{sever(&sub,&hsub);CreateGList(&p->tp,hsub);p=p->tp;};}return OK;}Status DestroyGList(GList *L){ /销毁⼴义表/GList ph,pt;if(*L) /L不为空表/{if((*L)->tag) /当L是⼦表/ph=(*L)->a.hp;else /当L是原⼦/ph=NULL;pt=(*L)->tp;free(*L); /释放L所指结点/*L=NULL;DestroyGList(&ph); /递归销毁表ph /DestroyGList(&pt); /递归销毁表pt /}return OK;}Status CopyGList(GList *T,GList L)*T=NULL;return OK;}*T=(GList)malloc(sizeof(GLNode));if(!*T)exit(OVERFLOW);(*T)->tag=L->tag;if(L->tag==ATOM) /复制共⽤体部分/(*T)->a.atom=L->a.atom; /复制单原⼦/ elseCopyGList(&(*T)->a.hp,L->a.hp); /复制⼦表/ if(L->tp==NULL)(*T)->tp=L->tp;elseCopyGList(&(*T)->tp,L->tp); /复制⼦表/ return OK;}int GListLength(GList L){ /求⼴义表L的长度/int len=0;GList p;if(L->tag==LIST&&!L->a.hp) /空表/return 0;else if(L->tag==ATOM) /单原⼦表/return 1;else /⼀般表/{p=L->a.hp;do{len++;p=p->tp;}while(p);}int GListDepth(GList L){ /求⼴义表L的深度/int max,dep;GList pp;if(L==NULL||L->tag==LIST&&!L->a.hp)return 1; /空表深度为1/else if(L->tag==ATOM)return 0; /单原⼦表深度为0 /else /求⼀般表的深度/for(max=0,pp=L->a.hp;pp;pp=pp->tp){dep=GListDepth(pp);if(dep>max)max=dep;}return max+1; /⾮空表的深度是各元素的深度的最⼤值加1 / } Status GListEmpty(GList L){ /判定⼴义表L是否为空/if(!L||L->tag==LIST&&!L->a.hp)return OK;elsereturn ERROR;}GList GetHead(GList L){ /取⼴义表表头/GList h;InitGList(&h);if(!L||L->tag==LIST&&!L->a.hp){printf("\n空表⽆表头!");exit(0);}exit(OVERFLOW);h->tag=L->a.hp->tag;h->tp=NULL;if(h->tag==ATOM)h->a.atom=L->a.hp->a.atom;elseCopyGList(&h->a.hp,L->a.hp->a.hp);return h;}GList GetTail(GList L){ /取⼴义表表尾/GList T;if(!L){printf("\n空表⽆表尾!");exit(0);}T=(GList)malloc(sizeof(GLNode));if(!T)exit(OVERFLOW);T->tag=LIST;T->tp=NULL;CopyGList(&T->a.hp,L->a.hp->tp);return T;}Status InsertFirst_GL(GList *L,GList e){ /插⼊元素e作为⼴义表L的第⼀元素/ GList p=(*L)->a.hp; (*L)->a.hp=e;e->tp=p;return OK;}Status DeleteFirst_GL(GList *L,GList *e){ /删除⼴义表L的第⼀元素,并⽤e返回其值/ if(*L)(*L)->a.hp=(*e)->tp;(*e)->tp=NULL;}else*e=*L;return OK;}void Traverse_GL(GList L,void(*v)(AtomType)) { /遍历⼴义表/GList hp;if(L){if(L->tag==ATOM) /L是原⼦/{v(L->a.atom);hp=NULL;}else /L是⼦表/hp=L->a.hp;Traverse_GL(hp,v);Traverse_GL(L->tp,v);}}void visit(AtomType e){printf("%c ", e);}void main() /主函数/{char p[80];GList l,m;HString t;InitString(&t);Status Eflag;int x;int d;do{E flag=TRUE;d o{system("cls");printf("\n***************************************************"); printf("\n1:建⽴空⼴义表");printf("\n2:由字符串建⽴⼴义表");printf("\n3:退出");printf("\n***************************************************"); printf("\n请选择功能:");scanf("%d",&x);switch(x){case 1: if(InitGList(&l)){printf("\n建表成功!");getch();}else{printf("\n建表失败!");getch();Eflag=FALSE;}break;case 2: printf("\n请输⼊合法的⼴义表书写形式"); printf("\n格式如:(),(a,b),(a,(),b),(a,(c,d),f)");printf("\n输⼊字符串:");if(CreateGList(&l,t)){printf("\n建表成功!");getch();}else{printf("\n建表失败!");getch();Eflag=FALSE;}break;case 3: printf("\n感谢使⽤本软件!");getch();exit(0);default: printf("\n输⼊错误!请重新输⼊!");getch();}}w hile(x!=1&&x!=2||!Eflag);d o{Status Eflag=TRUE;system("cls");printf("\n***************************************************"); printf("\n1:复制⼴义表");printf("\n2:求⼴义表长度");printf("\n3:求⼴义表深度");printf("\n4:判断⼴义表是不是空表");printf("\n5:取⼴义表表头");printf("\n6:取⼴义表表尾");printf("\n7:头结点插⼊元素");printf("\n8:删除第⼀个元素");printf("\n11:退出");printf("\n***************************************************"); printf("\n请选择功能:");printf("\n请输⼊你要选择的功能:");scanf("%d",&x);switch(x){case 1: if(CopyGList(&m,l)){printf("\n复制成功!");getch();}break;。
数组与广义表的算法的实验报告

数组与广义表的算法实验工具:visual C++实验内容:1、三元组表示稀疏矩阵的转置算法(一般&快速)<1-7页> 2、稀疏矩阵乘法、加法的算法(一般&十字链表)<8-21页> 3、广义表的各种算法<22-28页> 体验:通过利用visual C++实验工具,实现数组与广义表各类算法的过程中,本人对数组与广义表的知识有了更深的了解,而且认识到数组与广义表各类操作可由形式多样的算法结构实现。
算法并非统一标准的,同样的结果可有多种算法得出,算法的编写鼓励创造性思维。
1、三元组表示稀疏矩阵的转置算法(一般&快速)代码:#include<stdio.h>#include<conio.h>#include<stdlib.h>#include<windows.h>#define OK 1#define ERROR 0#define OVERFLOW 0#define MAXSIZE 100#define MAXRC 100typedef int ElemType;typedef struct{int i,j;ElemType e;}Triple;typedef struct{Triple data[MAXSIZE+1]; //非零元三元组int rpos[MAXRC+1]; //各行第一个非零元的位置表int mu,nu,tu; //矩阵的行数、列数和非零元个数}RLSMatrix;CreateSMatrix(RLSMatrix &M) //创建稀疏矩阵M{int i,m,n;ElemType e;int k,j;printf("输入矩阵的行数、列数、非零元的个数:");scanf("%d%d%d",&M.mu,&M.nu,&M.tu);M.data[0].i=0;for(i=1;i<=M.tu;i++){j=0;do{j++;if(j>3) //控制跳出死循环{printf("本次输入失败!");return ERROR;}printf("按行序输入第%d个非零元素所在的行(1~%d)列(1~%d)值:",i,M.mu,M.nu);scanf("%d%d%d",&m,&n,&e);k=0;if(m<1||m>M.mu||n<1||n>M.nu) //行或列超出范围k=1;if(m<M.data[i-1].i||m==M.data[i-1].i&&n<M.data[i-1].j)k=1;}while(k);M.data[i].i=m;M.data[i].j=n;M.data[i].e=e;} //end forprintf("\n");return(OK);}void DestroySMatrix(RLSMatrix &M) //销毁稀疏矩阵M{M.mu=0;M.nu=0;M.tu=0;}void PrinRLSMatrix(RLSMatrix M) //遍历稀疏矩阵M{int i;printf("稀疏矩阵对应的三元组表为:\n\n");printf("行列元素值、\n\n");for(i=1;i<=M.tu;i++)printf("%2d%4d%8d\n",M.data[i].i,M.data[i].j,M.data[i].e);printf("\n\n");}void print(RLSMatrix A) //打印矩阵函数,以通常形式输出矩阵{int k=1,a,b;printf("稀疏矩阵的通常形式为:\n");int M[MAXSIZE][MAXSIZE];for(a=0;a<A.mu;a++) //初始化矩阵M{for(b=0;b<A.nu;b++)M[a][b]=0;}while(k<=A.tu){M[A.data[k].i-1][A.data[k].j-1]=A.data[k].e;k++;}for(a=0;a<A.mu;a++){printf(" | ");for(b=0;b<A.nu;b++)printf("%d ",M[a][b]);printf(" | \n");}}void showtip() //菜单{printf(" ********************请选择要执行的操作********************\n\n");printf(" & 1 采用一般算法实现&\n");printf(" & 2 采用快速转置的算法实现&\n");printf(" & 3 同时采用两种算法,先显示一般算法,再显示快速算法&\n");printf(" **********************************************************\n\n");}////头文件结束TransposeSMatrix(RLSMatrix M,RLSMatrix &T) //求稀疏矩阵M的转置矩阵T(一般算法) {int p,q,col;T.mu=M.nu;T.nu=M.mu;T.tu=M.tu;if(T.tu){q=1;for(col=1;col<=M.nu;++col) //按列序求转置for(p=1;p<=M.tu;++p)if(M.data[p].j==col){T.data[q].i=M.data[p].j;T.data[q].j=M.data[p].i;T.data[q].e=M.data[p].e;++q;}}return OK;}FastTransposeSMatrix(RLSMatrix M,RLSMatrix &T) //快速转置算法{int p,q,t,col,*num,*cpot;num=(int*)malloc((M.nu+1)*sizeof(int));cpot=(int*)malloc((M.nu+1)*sizeof(int));T.mu=M.nu;T.nu=M.mu;T.tu=M.tu;if(T.tu){for(col=1;col<=M.nu;++col)num[col]=0;for(t=1;t<=M.tu;++t)++num[M.data[t].j];cpot[1]=1;for(col=2;col<=M.nu;++col)cpot[col]=cpot[col-1]+num[col-1];printf("\n辅助数组的值为:\n");printf("列号:");for(t=1;t<=M.nu;++t)printf("%4d",t);printf("\n");printf("num[]");for(t=1;t<=M.nu;++t)printf("%4d",num[t]);printf("\n");printf("cpot[]");for(t=1;t<=M.nu;++t)printf("%4d",cpot[t]);printf("\n\n");for(p=1;p<=M.tu;++p){col=M.data[p].j;q=cpot[col];T.data[q].i=M.data[p].j;T.data[q].j=M.data[p].i;T.data[q].e=M.data[p].e;++cpot[col];}}free(num);free(cpot);return OK;}void main(){int result;int j;RLSMatrix A,B;//************************************************COORD Co={0,0};DWORD Write;SetConsoleTitle("稀疏矩阵的转置\n");HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleTextAttribute(hOut,FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND _INTENSITY);FillConsoleOutputAttribute(hOut,FOREGROUND_RED|FOREGROUND_BLUE|FOREGROU ND_INTENSITY,100000000,Co,&Write);///windows的API函数,用来设置控制台标题do{showtip(); //调用菜单函数int i;scanf("%d",&i);switch(i){case 1:printf("创建矩阵A:");if((result=CreateSMatrix(A))==0)exit(ERROR);PrinRLSMatrix(A);printf("求A的转置矩阵B(一般算法):\n");TransposeSMatrix(A,B);PrinRLSMatrix(B);print(B);DestroySMatrix(B);printf("\n\n");break;case 2:printf("创建矩阵A:");if((result=CreateSMatrix(A))==0)exit(ERROR);PrinRLSMatrix(A);printf("求A的转置矩阵B(快速转置):\n");FastTransposeSMatrix(A,B);PrinRLSMatrix(B);print(B);DestroySMatrix(A);DestroySMatrix(B);printf("\n\n");break;case 3:printf("创建矩阵A:");if((result=CreateSMatrix(A))==0)exit(ERROR);PrinRLSMatrix(A);printf("求A的转置矩阵B------(一般算法):\n");TransposeSMatrix(A,B);PrinRLSMatrix(B);print(B);DestroySMatrix(B);printf("\n\n");printf("求A的转置矩阵B------(快速转置):\n");FastTransposeSMatrix(A,B);PrinRLSMatrix(B);print(B);DestroySMatrix(A);DestroySMatrix(B);printf("\n\n");break;}printf(" **********请选择是否继续输入其他稀疏矩阵?**********\n");printf(" 1 是,输入其他矩阵\n");printf(" 0 否,不输入\n");printf(" ****************************************************");fflush(stdin);//清除输入缓存区scanf("%d",&j);}while(j==1);}运行结果:(1)创建矩阵(2)一般转置(3)快速转置2、稀疏矩阵乘法、加法的算法(一般&十字链表)代码:#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){link p;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。
数据结构实验报告-数组和广义表

(*T).data[q].i=(*M).data[q].j;
(*T).data[q].j=(*M).data[q].i;
(*T).data[q].e=(*M).data[q].e;
}
}
}
Source.h
#include"header.h"
void main()
{
TSMatrix M,T;
CreateSMatrix(&M);
六、教师评语
签名:
日期:
成绩
Welcome To
Download !!!
欢迎您的下载,资料仅供参考!
#include<stdlib.h>
//稀疏矩阵的三元组顺序表存储
#define MAXSIZE 125 //非零元个数的最大值
typedef int ElemType;
typedef struct//三元组节点
{
int i,j;//非零元的行下标、列下标
ElemType e;//矩阵的元素值。
}Triple;
{
int *p,k,i,j;
int mu,nu,tu;
mu=(*M).mu;nu=(*M).nu;tu=(*M).tu;
p=(int *)malloc((nu+1ห้องสมุดไป่ตู้*sizeof(ElemType));//用来保存每行元素。
for(i=1;i<=mu;i++)
{
for(k=0;k<=nu;k++) p[k]=0;
《数据结构》实验报告
实验序号:7实验项目名称:数组和广义表
学 号
姓 名
专业班级
数组、串与广义表的实例解析与编程实现

∥等于T则计数器加1 return count;
}∥StrCount 算法4.27
目录
数组、串 与广义表 的实例解 析与编程 实现
2021年1月30日星期六
【例4-14】采用静态顺序存储结构存储字符串, 编写一个函数将串S1中的第i个字符到第j个字符之间 的字符(包括第i个和第j个字符)用S2替换,函数名为 Replace(&S1,i,j,S2)。
676=644+(2×n+2)×1 容易得到n为15,再把n代入公式可得: Loc(a45 )=Loc(a00 )+(i×n+j)×L =644+(4×15+5)×1 =709
目录
数组、串 与广义表 的实例解 析与编程 实现
2021年1月30日星期六
【例4-8】画出对称矩阵A的压缩存储结构。
1 2 3 5
目录
数组、串 与广义表 的实例解 析与编程 实现
2021年1月30日星期六
void Print(Array A){ ∥转换过后逐行打印二维数组中的元素
for(i=0;i<A.index[0];i++){ ∥逐行扫描
for(j=0;j<A.index[1];j++){
∥扫描每个元素 off=i*A.index[1]+j;
∥计算偏移量 printf("%3d",*(A.base+off));
} printf("\n"); ∥输完一行,换行打印 } }
算法4.25
目录
数组、串 与广义表 的实例解 析与编程 实现
实验五数组广义表及其应用

归地输出实数 FractionPart 的整数部分后,在变量 FractionPart 中只保留原数的小数部分; 函数 的功能是:输入参数为任意实数 N 及其小数位数
DecPlace,首先判断 N 是否为负数,如果是则输出负号“-” ,并将 N 转化成其相反数(正数) 处理;处理步骤如下: 1) 调用 RoundUp 按照保留小数位数四舍五入并置 N 值; 2) 将 N 的整数部分和小数部分分别存于 IntPart 和 FractionPart 中; 3) 输出 N 的整数部分; 4) 如果要求保留小数,则输出小数点“.” ;调用 PrintFractionPart 函数按照保留的小 数位数输出 N 的小数部分。 另可知:PrintDigit 函数编程如下: void PrintDigit(long n) { if( n >=10) PrintDigit( n /10) putchar( n % 10 +'0); }
4、在 c5_3.h 中建立如下结构的广义表头尾链表存储结构(在报告书中分析并画出其结 构示意) ,在 bo5_3.cpp 中建立基于该结构的基本操作函数(11 项,见下述提示,函数 声明略) ;在 bo5_31.cpp 中利用实验四中 c4_1.h 和 bo4_1.cpp 建立基于串结构的广义表 字符串表示输出函数(算法 5.7 和 5.8) ;在 main5_3.cpp 中完成测试验证函数,要求完 成对全部 11 项操作的基本测试。 (报告分析书写中要求对于主要操作函数的原理给予解 释,至少详细分析算法 5.5、5.6、和 5.7,并结合测试数据给出分析) 。
提示:c5_2.h 源程序
-4-
第四章 串
bo5_2.cpp 源程序(各函数出现次序如无相互调用,可自由安排)
实验六 串与广义表的存储与运算

实验六串与广义表的存储与运算实验题1:实现顺序串的各种基本运算目的:领会顺序串存储结构和掌握顺序串中的各种基本运算算法设计。
内容:编写一个程序sqstring.cpp,实现顺序串的各种基本运算,并在此基础上设计一个主程序完成如下功能:(1)建立串s="abcdefghefghijklmn"和串s=“xyz”。
(2)输出串s。
(3)输出串s的长度。
(4)在串s的第9个字符位置插入串s1而产生串s2。
(5)输出串s2。
(6)删除串s第2个子放入开始的5个字符而产生串s2。
(7)输出串s2。
(8)将串s第2个字符开始的5个字符替换成串s1而产生串s2。
(9)输出串s3。
(10)提取串s的第2个字符开始的10个字符而产生串s3。
(11)输出串s3。
(12)将串s1和串s2连接起来而产生串s4。
(13)输出串s4。
参考代码:#include "sqstring.cpp"//包含顺序串基本运算算法int main(){SqString s,s1,s2,s3,s4;printf("顺序串的基本运算如下:\n");printf(" (1)建立串s和串s1\n");StrAssign(s,"abcdefghijklmn");StrAssign(s1,"123");printf(" (2)输出串s:");DispStr(s);printf(" (3)串s的长度:%d\n",StrLength(s));printf(" (4)在串s的第9个字符位置插入串s1而产生串s2\n");s2=InsStr(s,9,s1);printf(" (5)输出串s2:");DispStr(s2);printf(" (6)删除串s第2个字符开始的5个字符而产生串s2\n");s2=DelStr(s,2,3);printf(" (7)输出串s2:");DispStr(s2);printf(" (8)将串s第2个字符开始的5个字符替换成串s1而产生串s2\n");s2=RepStr(s,2,5,s1);printf(" (9)输出串s2:");DispStr(s2);printf(" (10)提取串s的第2个字符开始的10个字符而产生串s3\n");s3=SubStr(s,2,10);printf(" (11)输出串s3:");DispStr(s3);printf(" (12)将串s1和串s2连接起来而产生串s4\n");s4=Concat(s1,s2);printf(" (13)输出串s4:");DispStr(s4);DestroyStr(s); DestroyStr(s1); DestroyStr(s2);DestroyStr(s3); DestroyStr(s4);return 0;}//顺序串基本运算的算法#include <stdio.h>#define MaxSize 100typedef struct{char data[MaxSize];//串中字符int length;//串长} SqString;//声明顺序串类型void StrAssign(SqString &s,char cstr[])//字符串常量赋给串s{int i;for (i=0;cstr[i]!='\0';i++)s.data[i]=cstr[i];s.length=i;}void DestroyStr(SqString &s)//销毁串{ }void StrCopy(SqString &s,SqString t)//串复制{for (int i=0;i<t.length;i++)s.data[i]=t.data[i];s.length=t.length;}bool StrEqual(SqString s,SqString t)//判串相等{bool same=true;if (s.length!=t.length)//长度不相等时返回0 same=false;elsefor (int i=0;i<s.length;i++)if (s.data[i]!=t.data[i])//有一个对应字符不相同时返回假{same=false;break;}return same;}int StrLength(SqString s)//求串长{return s.length;}SqString Concat(SqString s,SqString t)//串连接{SqString str;int i;str.length=s.length+t.length;for (i=0;i<s.length;i++)//s.data[0..s.length-1]→strstr.data[i]=s.data[i];for (i=0;i<t.length;i++)//t.data[0..t.length-1]→strstr.data[s.length+i]=t.data[i];return str;}SqString SubStr(SqString s,int i,int j)//求子串{SqString str;int k;str.length=0;if (i<=0 || i>s.length || j<0 || i+j-1>s.length)return str;//参数不正确时返回空串for (k=i-1;k<i+j-1;k++) //s.data[i..i+j]→strstr.data[k-i+1]=s.data[k];str.length=j;return str;}SqString InsStr(SqString s1,int i,SqString s2)//插入串{int j;SqString str;str.length=0;if (i<=0 || i>s1.length+1)//参数不正确时返回空串return str;for (j=0;j<i-1;j++) //s1.data[0..i-2]→strstr.data[j]=s1.data[j];for (j=0;j<s2.length;j++)//s2.data[0..s2.length-1]→str str.data[i+j-1]=s2.data[j];for (j=i-1;j<s1.length;j++)//s1.data[i-1..s1.length-1]→str str.data[s2.length+j]=s1.data[j];str.length=s1.length+s2.length;return str;}SqString DelStr(SqString s,int i,int j)//串删去{int k;SqString str;str.length=0;if (i<=0 || i>s.length || i+j>s.length+1) //参数不正确时返回空串return str;for (k=0;k<i-1;k++) //s.data[0..i-2]→strstr.data[k]=s.data[k];for (k=i+j-1;k<s.length;k++)//s.data[i+j-1..s.length-1]→str str.data[k-j]=s.data[k];str.length=s.length-j;return str;}SqString RepStr(SqString s,int i,int j,SqString t)//子串替换{int k;SqString str;str.length=0;if (i<=0 || i>s.length || i+j-1>s.length) //参数不正确时返回空串return str;for (k=0;k<i-1;k++)//s.data[0..i-2]→strstr.data[k]=s.data[k];for (k=0;k<t.length;k++) //t.data[0..t.length-1]→str str.data[i+k-1]=t.data[k];for (k=i+j-1;k<s.length;k++)//s.data[i+j-1..s.length-1]→str str.data[t.length+k-j]=s.data[k];str.length=s.length-j+t.length;return str;}void DispStr(SqString s)//输出串s{if (s.length>0){for (int i=0;i<s.length;i++)printf("%c",s.data[i]);printf("\n");}}实验题2:实现链串的各种基本运算的算法目的:领会链串存储结构和掌握链串中的各种基本运算算法设计。
广义表实验报告

广义表实验报告一、实验目的广义表是一种非线性的数据结构,本次实验的主要目的是深入理解广义表的概念、存储结构和基本操作,并通过编程实现对广义表的各种操作,以提高对数据结构的理解和编程能力。
二、实验环境本次实验使用的编程语言是C++,编译环境为Visual Studio 2019。
三、广义表的概念广义表是线性表的推广,它允许表中的元素本身也是一个广义表。
广义表通常用一对圆括号“()”来表示,元素之间用逗号“,”分隔。
例如,(a, (b, c), d) 就是一个广义表,其中 a、d 是原子元素,(b, c) 是子表。
广义表可以分为表头和表尾两部分。
表头是广义表的第一个元素,表尾是除表头外的其余元素组成的广义表。
例如,对于广义表(a, (b,c), d),表头是 a,表尾是((b, c), d)。
四、广义表的存储结构1、头尾链表存储结构每个节点包含一个标志位 tag,用于区分原子节点和子表节点。
当 tag = 0 时,为原子节点,包含一个数据域 atom 和一个指向下一个节点的指针 next。
当 tag = 1 时,为子表节点,包含一个指向表头节点的指针 hp 和一个指向表尾节点的指针 tp。
2、扩展线性链表存储结构每个节点包含一个标志位 tag、一个数据域 data 和两个指针域 hp和 tp。
当 tag = 0 时,data 存储原子元素的值,hp 和 tp 均为 NULL。
当 tag = 1 时,data 为 NULL,hp 指向表头节点,tp 指向表尾节点。
五、广义表的基本操作1、创建广义表输入广义表的字符串表示,通过递归算法构建广义表的存储结构。
2、输出广义表以递归的方式遍历广义表的存储结构,输出广义表的字符串表示。
3、求广义表的深度递归地计算每个子表的深度,广义表的深度为所有子表深度的最大值加 1。
4、求广义表的长度遍历广义表的存储结构,统计原子节点和子表节点的个数。
5、复制广义表递归地复制广义表的每个节点,创建一个新的广义表存储结构。
数组和广义表课程设计

数组和广义表课程设计一、教学目标本节课的学习目标主要包括以下三个方面:1.知识目标:通过本节课的学习,学生需要掌握数组和广义表的基本概念、性质和运算方法。
具体包括了解数组和广义表的定义、特点和应用场景,掌握数组的创建、访问和修改方法,以及广义表的创建、展开和递归操作。
2.技能目标:学生需要能够运用数组和广义表解决实际问题,具备一定的编程能力。
具体包括能够使用数组进行数据存储和处理,能够使用广义表进行复杂数据的表示和操作。
3.情感态度价值观目标:通过学习数组和广义表,学生能够培养对计算机科学的兴趣和热情,增强对算法和数据结构的理解和认识,提高解决问题的能力和创新思维。
二、教学内容本节课的教学内容主要包括数组和广义表的基本概念、性质和运算方法。
具体包括以下几个方面:1.数组的概念和性质:介绍数组的定义、特点和应用场景,讲解数组的创建、访问和修改方法。
2.广义表的概念和性质:介绍广义表的定义、特点和应用场景,讲解广义表的创建、展开和递归操作。
3.数组的运算方法:讲解数组的排序、查找和动态扩容等运算方法。
4.广义表的运算方法:讲解广义表的深度、广度、求表长、求表元素等运算方法。
三、教学方法为了提高教学效果,本节课将采用多种教学方法相结合的方式进行教学。
具体包括以下几种方法:1.讲授法:通过教师的讲解,引导学生了解数组和广义表的基本概念、性质和运算方法。
2.案例分析法:通过分析实际案例,让学生掌握数组和广义表在解决实际问题中的应用。
3.实验法:安排课后的实验环节,让学生亲自动手操作,加深对数组和广义表的理解。
4.讨论法:学生进行小组讨论,促进学生之间的交流与合作,提高解决问题的能力。
四、教学资源为了支持本节课的教学内容和教学方法的实施,我们将准备以下教学资源:1.教材:选用《数据结构与算法》等教材,为学生提供系统的理论知识。
2.参考书:提供《计算机程序设计艺术》等参考书,丰富学生的知识体系。
3.多媒体资料:制作数组和广义表的PPT课件,以直观的方式展示数组和广义表的运算过程。
数据结构实验报告_9

本科生实验报告(二)姓名:学院:专业:班级:实验课程名称: 数据结构实验日期: 2013年 5月 25 日指导教师及职称:实验成绩:开课时间:2012~2013 学年第二学期k++;a[j][n-i-1]=k;}for (j=n-i-2;j>=i;j--){k++;a[n-i-1][j]=k;}for (j=n-i-2;j>=i+1;j--){k++;[j][i]=k;}}}void main(){int n,i,j;int a[MaxLen][MaxLen];printf("输入n(n<10):");scanf("%d",&n);fun(a,n);printf("%d阶数字方阵如下:\n",n);for (i=0;i<n;i++){for (j=0;j<n;j++)printf("%4d",a[i][j]);printf("\n");}}运行结果:6.2:如果矩阵A中存在这样的一个元素A[i][j]满足条件:A[i][j]是第i行中值最小的元素,且又是第j列中值最大的元素,则称为该矩阵的一个马鞍点。
设计一个程序exp6-2.cpp 计算出m*n的矩阵A的所有马鞍点。
主程序如下:6.3:已知A和B为两个n*n阶的对称矩阵,输入时,对称矩阵只输入下三角形元素,存入一维数组,如图6.5所示(对称矩阵M存储在一维数组A中),设计一个程序exp6-3.cpp 实习如下功能:(1)求对称矩阵A和B的和。
(2)求对称矩阵A和B的乘积。
A:图6.5 对称矩阵的存储转换形式主程序如下:#include <stdio.h>#define N 4#define M 10int value(int a[],int i,int j){if (i>=j)return a[(i*(i-1))/2+j];elsereturn a[(j*(j-1))/2+i];}void madd(int a[],int b[],int c[][N]){int i,j;for (i=0;i<N;i++)printf("a+b:\n");disp2(c1);printf("a×b:\n");disp2(c2);printf("\n");}运行结果:6.4::假设n*n的稀疏矩阵A采用三元组表示,设计一个程序exp6-4.cpp实现如下功能:(1)生成如下两个稀疏矩阵矩阵的三元组a和b:(2)输出a转置矩阵的三元组;(3)输出a+b的三元组;(4)输出a*b的三元组。
数组实验报告实验分析

一、实验目的1. 理解数组的概念和基本操作。
2. 掌握数组的创建、初始化、访问和修改方法。
3. 学习数组的排序、查找和统计等常用算法。
4. 分析数组在实际应用中的优缺点。
二、实验内容1. 数组的创建与初始化2. 数组元素的访问与修改3. 数组的排序4. 数组的查找5. 数组的统计6. 数组在实际应用中的优缺点分析三、实验过程1. 数组的创建与初始化在实验中,我们首先学习了如何创建一个数组。
在C语言中,可以使用以下语句创建一个整型数组:int arr[10];这里创建了一个包含10个整数的数组,名称为arr。
接下来,我们学习了如何初始化数组。
初始化可以通过以下语句实现:int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};这里初始化了一个包含10个整数的数组,并将前10个整数依次赋值给数组元素。
2. 数组元素的访问与修改访问数组元素可以通过以下语句实现:int value = arr[3]; // 获取数组第4个元素的值修改数组元素可以通过以下语句实现:arr[5] = 20; // 将数组第6个元素的值修改为203. 数组的排序在实验中,我们学习了冒泡排序算法。
冒泡排序是一种简单的排序算法,其基本思想是通过比较相邻的元素,将较大的元素交换到数组的后面。
以下是冒泡排序算法的C语言实现:void bubbleSort(int arr[], int n) {int i, j, temp;for (i = 0; i < n - 1; i++) {for (j = 0; j < n - i - 1; j++) {if (arr[j] > arr[j + 1]) {temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}}4. 数组的查找在实验中,我们学习了二分查找算法。
二分查找算法是一种高效的查找算法,其基本思想是将查找区间分为两半,每次查找时缩小查找范围。
实验 二维数组和广义表

实验二维数组和广义表一、实验目的1.熟悉数组类型的实现2.掌握使用数组实现特殊矩阵的压缩存储3.掌握稀疏矩阵的三元组表示法的实现通过本次实习加深对高级语言C语言的使用,熟悉数组在C语言中的实现二、实验内容采用压缩顺序存储法,能够对于给定一组“合法”的下标(i,j)对应的元素a ij,进行存取运算;三、实验报告要求1.上机前完成所有的函数编写2.主要实验设备(软件)部分填写:装有TC软件的普通PC机3.实验记录部分填写编写主函数调用所写所有函数的屏幕输出4.设备名称填写PC机,型号可空,编号填写所使用计算机编号,运行情况填写良好5.实验总结部分写出AccessTSMatrix函数中i,j,k分别代表什么;main函数中i,r,c分别代表什么四、实验原理矩阵是很多的科学与工程计算中研究的数学对象。
在此,我们感兴趣的是,从数学结构这门学科着眼,如何存储矩阵的元从而使矩阵的各种运算有效的进行。
本来,用二维数组存储矩阵,在逻辑上意义是很明确的,也很容易理解,操作也很容易和方便。
但是在数值分析中经常出现一些阶数很高的矩阵,同时,在矩阵中又有很多值相同或者都为零的元素,可以对这种矩阵进行压缩存储:对多个值相同的元素只分配一个存储空间;对零元素不分配空间。
稀疏矩阵的定义是一个模糊的定义:即非零元个数较零元个数较少的矩阵。
例如下图所示的矩阵:012 9 0 0 0 000 0 0 0 0 030 0 0 0 14 000 24 0 0 0 0018 0 0 0 0 0150 0 -7 0 0 0为一个稀疏矩阵。
为了实现稀疏矩阵的这种存储结构,引入三元组这种数据结构。
三元组的线性表顺序存储形式如下图:行列值行列值行列值……行列值1 2 12 1 3 9 3 1 3 …… 6 4 -7五、参考程序算法思想:用线性表的顺序查找算法,在存储稀疏矩阵的数组中查找三元组中行列号(row,col)等于(i,j)的数组元素,若查找到,则可以通过数组元素的三元组中读取到元素的值val;若查找不到,则返回0参考程序:实验数据及结果:六、实验步骤1.参考实验程序自己编出程序,上机调试。
数组和广义表学习

中南大学《数据结构与算法》数组与广义表学习报告学习报告数组与广义表学习报告A 数组1学习目标:进一步深刻的了解数组的定义与运算,对数组的顺序存储结构更深入的认知。
也是对曾经学过的知识的进一步巩固。
更重要的是学习特殊矩阵的压缩存储方法实现矩阵之间的加减运算,如三角矩阵,对称矩阵,以及稀疏矩阵的一些基本操作。
2学习过程:数组是一种数据类型。
从逻辑结构上看,数组可以看成是一般线性表的扩充。
二维数组可以看成是线性表的线性表,应此可以利用线性表来存储多维数组。
把多维数组尤其是二维数组转换为线性表尤为重要,二维数组可以作为一个矩阵看待我们还可以将数组A m×n看成另外一个线性表:B=(β1,,β2,,… ,βm),其中βi(1≤i ≤m)本身也是一个线性表,称为行向量,即:βI= (a i1,a i2,…,a ij ,…,a in)。
这样把二维数组转换为了一维数组就能很轻松的进行操作与运算了。
数组的抽象数据类型定义(ADT Array)数据对象:D={ a j1j2…jn| n>0,称为数组的维数,j i是数组的第i维下标,1≤j i≤b i,bi为数组第i维的长度,a j1j2…jn∈ElementSet}基本操作:包括initArray(), destoryArray(), getElement(), setElement()1先实现了一位动态数组的存储#include<iostream>using namespace std;void main(){int *a ,n=10;int i;a=(int *)calloc(n,sizeof(int));for(i=0;i<n;i++)a[i]=i+1;for (i=0;i<n;i++)cout<<a[i]<<"\t";free(a);}通过实现了这个程序学到了更进一步的知道了如何动态申请内存空和释放动态深情的数组内存空间的calloc()函数,其函数原型为(void*)calloc(unsigned n ,sizeof(int))。
数据结构实验广义表

《数据结构》实验报告实验题目:广义表的创建与遍历实验目的:熟悉和掌握广义表的定义及结构,可以创建及遍历广义表。
实验内容:利用栈创建以及遍历一个广义表。
一、需求分析1.本演示程序中,输入广义表的内容应为任意符合广义表要求结构的数据,将数据输入创建广义表中,再通过遍历程序将其以广义表形式输出。
2.本程序是以用户与计算机的对话方式执行,运行程序后,按要求输入数据即可。
3.程序执行的命令包括:(1)构造广义表与链栈,并初始化(2)输入广义表(3)输出广义表(4)结束4.测试数据:输入((),((a,b),(c,d))) 输出((),((a,b),(c,d)))错误输入:如果输入((),((a,b),(c,d)))) 输出((),((a,b),(c,d)))二概要设计为了实现上述操作,应以广义链表为存储结构。
1.基本操作:Snode *Push(Snode *top,node *input)实现指针入栈Snode *Pop(Snode *top,node **output)实现指针出栈node *create()广义表的建立void print(node *head)广义表的输出2.本程序包括三个模块:(1)主程序模块(2)广义表的创建(3)广义表的遍历(4)入栈模块(5)出栈模块(6)模块调用图:三 详细设计1.元素类型、节点类型和指针类型//定义广义表typedef struct node{char data; /*存储数据*/int tag; /*用以标记,标记为1时为左括号,标记为0时为字符,标记为-1时为新开辟节点*/struct node *hp; /*该指针指向字表*/struct node *tp; /*该指针指向后续节点*/}node;//定义链栈typedef struct Snode{node *data;struct Snode *next;}Snode;Snode *topnode *inputSnode *sSnode *p;node **outputnode *p,*q,*head;2.每个模块的分析:(1) 主程序模块:int main(){node *head;printf("请输入广义表:\n");head=create();printf("该广义表为:\n");print(head);getchar();getchar();return 0;}(2)广义表的创建:node *create(){node *p,*q,*head; /*指针p是一个移动指针,指针q用以开辟新节点,head为头指针*/char x; /*输入字符*/Snode *top; /*栈顶指针*/top=NULL; /*栈顶置空*/q=(node *)malloc(sizeof(node)); /*申请新节点*/q->tag=1; /*广义表形式第一个字符必为左括号*/scanf("%c",&x); /*输入字符*/head=q; /*广义表头结点指向新开辟节点*/p=head; /*活动指针指向头结点*/top=Push(top,p); /*该节点指针入栈*/q=(node *)malloc(sizeof(node)); /*开辟新节点*/q->tag=-1; /*新节点标记为-1*/p->hp=q; /*上一个读到的是左括号,将新节点链到当前节点的子表*/p->tag=1; /*当前节点为左括号,标记为1*/p->data=NULL; /*当前节点数据域为空*/p=p->hp; /*活动指针移到当前节点的子表*/scanf("%c",&x); /*接着输入数据*/while(top!=NULL) /*遇到左括号进栈,右括号退栈,栈空循环结束*/{if(x=='(') /*遇到左括号*/{q=(node *)malloc(sizeof(node)); /*申请新节点*/q->tag=-1; /*新节点标记均为-1*/p->hp=q; /*新节点链到当前节点的子表*/p->tag=1; /*因是左括号,当前节点标记为1*/p->data=NULL; /*数据域为空*/top=Push(top,p); /*指针入栈*/p=p->hp; /*移动指针到当前节点的子表*/}else if(x==',') /*遇到逗号*/{q=(node *)malloc(sizeof(node)); /*申请新节点,标记-1*/q->tag=-1;p->tp=q; /*新节点链到当前节点后续节点*/p=p->tp; /*移动指针到当前节点的后续*/}else if(x==')') /*遇到右括号*/{p->tp=NULL; /*后续域置空*/top=Pop(top,&p); /*栈顶指针退栈*/ }else /*遇到其他字符*/{p->tag=0; /*标记为0*/p->data=x; /*数据域存数据*/p->hp=NULL; /*子表指向置空*/ }scanf("%c",&x); /*再读下一个字符*/ }p->tp=NULL; /*循环结束,当前节点后续置空*/return(head);(3)广义表的遍历:void print(node *head){node *p;Snode *top;p=head;top=NULL; /*栈置空*/while(p!=NULL||top!=NULL) /*p空且栈空时退出循环*/{if(p!=NULL) /*如果活动指针不空,做三个判断*/{if(p->tag==1) /*标记为1输出左括号,指针进栈,活动指针下移*/{top=Push(top,p);printf("(");p=p->hp;}else if(p->tag==0) /*标记为0,输出字符,如果后续不空,输出逗号*/{printf("%c",p->data);if(p->tp!=NULL){printf(",");}p=p->tp;}else if(p->tag==-1) /*标记为-1,先出栈,出栈后p上移输出右括号,如果后续不空,输出逗号*/{top=Pop(top,&p);printf(")");if(p->tp!=NULL){printf(",");}p=p->tp;}}else /*若p空,表示该层结束*/{top=Pop(top,&p); /*退栈,指针上移,若上移后仍不为空,且此时栈必定不空,输出右括号*/printf(")");if(p->tp!=NULL) /*若后续不为空,需输出逗号,指针后移*/{printf(",");}p=p->tp;}}printf("\n");}(4)入栈模块:Snode *Push(Snode *top,node *input){Snode *s;s=(Snode *)malloc(sizeof(Snode)); /*申请新节点*/s->data=input;s->next=top;top=s;return(top);}(5)出栈模块:Snode *Pop(Snode *top,node **output){Snode *p;if (top==NULL){*output=NULL;return NULL;}else{*output=top->data;p=top;top=top->next;free(p);return(top);}}3.完整的程序:(见源文件).四使用说明、测试分析及结果1.程序使用说明:(1)本程序的运行环境为VC6.0。
广义表实验报告

数据结构实验报告题目:广义表抽象数据类型的实现学院计算机学院专业计算机科学与技术年级班别 2010级7班学号学生指导教师成绩 ____________________2012年6月1. 题目实现广义表抽象数据类型GListADT GList{数据对象:D={ e i| i=1,2,...,n; n≥0;e i∈AtomSet或e i∈GList,AtomSet为某个数据对象}数据关系:R1={ <e i-1,e i>|e i-1, e i∈D, 2<=i<=n }基本操作:InitGlist(&L);操作结果:创建空的广义表LCreateGList(&L,S);初始条件:S是广义表的书写形式串操作结果:由S创建广义表LDestroyGlist(&L);初始条件:广义表L存在操作结果:销毁广义表LCopyGlist(&T,L);初始条件:广义表L存在操作结果:由广义表L复制得到广义表TGListLength(L);初始条件:广义表L存在操作结果:求广义表L的长度,即元素个数GListDepth(L);初始条件:广义表L存在操作结果:求广义表L的深度GlistEmpty(L);初始条件:广义表L存在操作结果:判断广义表L是否为空GetHead(L);初始条件:广义表L存在操作结果:取广义表L的头GetTail(L)初始条件:广义表L存在操作结果: 取广义表L的尾InsertFirst_GL(&L,e)初始条件:广义表L存在操作结果:插入元素e作为广义表L的第一元素DeleteFirst_GL(GList &L,&e)初始条件:广义表L存在操作结果:删除广义表L的第一元素,并用e返回其值Traverse_GL(GList L,void(*v)(AtomType))初始条件:广义表L存在操作结果:遍历广义表L,用函数Visit处理每个元素}ADT GList2.存储结构定义由于广义表中的数据元素可以具有不同的结构(或是原子,或是列表),因此难以用顺序存储结构表示,通常采用链式存储结构,每个数据元素可用一个节点表示。
数组和广义表的学习心得

数组是用来存储同一种数据类型的数据的一种数据结构。
1、普通的一维数组是用来实现一些线性结构的好助手,例如我们使用的线性表的顺序存储,栈的顺序存储,队列的顺序存储,这里面都要-用到数组作为存储成部分。
2、经过扩展的二维数组,作用将更加明显,我们使用扩展的二维数组来存储矩阵。
而实际在工程的计算中矩阵的使用情况是十分普遍的。
我们将用到矩阵的加减法,这些必须都要投影到二维数组上进行计算,我们一般在使用二维数组时将会使用按行优先存储。
我们的教材中就会有非常明显的表现,在矩阵转置的算法中,我们就会使用到二维数组按行优先的存储,跳着找顺着存时,我们会将所有的列进行遍历,找到原来矩阵中某个元素的列值和现在这时for循环的列值是相等的。
将这个元素存储到相应现在这个三元组表中的位置。
即按列的顺序找,然后按顺序存入三元组中。
3、和数组相关的还有矩阵的压缩存储。
我们平时使用的数组中有些是非常特别的,例如有些数组中仅仅只有下三角部分是一些不同的元素,其余部分全是0.这个时候,我们从节省存储空间的角度考虑,我们可以使用矩阵的压缩存储。
我们使用一个一维数组来按行优先的顺序来存储这个矩阵,下三角矩阵是对称的,因此我们只在这个一维数组中存储下三角中的数据。
其余0的部分可以不存储,或者就是用一个存储单元来存储。
有以上所述,我们很自然的就想到将数组引申到矩阵的存储上来接着讨论。
存储特殊矩阵的时候,例如我们在存储下三角矩阵的时候,我们使用的是一维数组,将下三角按照行优先的顺序存储所有的数据。
在这个过程中,我们确定元素的下表是这样来的。
a ij的下标是这样的:k = i*(i+1)/2+j ,现在以k做下标来存储这个元素。
矩阵的存储。
特殊矩阵的存储我们可以使用一维数组来压缩存储。
普通矩阵的存储我猜想可以直接使用二维数组了。
但对稀疏矩阵的存储,我们应该使用三元组来存储。
我们直接记录非零元素所在的行标和列标和元素值。
很显然这将也会是一个一维数组,但是这个一维数组的数组元素不是普通的数据类型,他们是可以看成是一个个的单元格,这个单元格的特殊之处就是他们的成员有三个,行标,列标,元素值。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
数组与广义表的算法实验工具:visual C++实验容:1、三元组表示稀疏矩阵的转置算法(一般&快速)<1-7页> 2、稀疏矩阵乘法、加法的算法(一般&十字链表)<8-21页> 3、广义表的各种算法<22-28页> 体验:通过利用visual C++实验工具,实现数组与广义表各类算法的过程中,本人对数组与广义表的知识有了更深的了解,而且认识到数组与广义表各类操作可由形式多样的算法结构实现。
算法并非统一标准的,同样的结果可有多种算法得出,算法的编写鼓励创造性思维。
1、三元组表示稀疏矩阵的转置算法(一般&快速)代码:#include<stdio.h>#include<conio.h>#include<stdlib.h>#include<windows.h>#define OK 1#define ERROR 0#define OVERFLOW 0#define MAXSIZE 100#define MAXRC 100typedef int ElemType;typedef struct{int i,j;ElemType e;}Triple;typedef struct{Triple data[MAXSIZE+1]; //非零元三元组int rpos[MAXRC+1]; //各行第一个非零元的位置表int mu,nu,tu; //矩阵的行数、列数和非零元个数}RLSMatrix;CreateSMatrix(RLSMatrix &M) //创建稀疏矩阵M{int i,m,n;ElemType e;int k,j;printf("输入矩阵的行数、列数、非零元的个数:");scanf("%d%d%d",&M.mu,&M.nu,&M.tu);M.data[0].i=0;for(i=1;i<=M.tu;i++){j=0;do{j++;if(j>3) //控制跳出死循环{printf("本次输入失败!");return ERROR;}printf("按行序输入第%d个非零元素所在的行(1~%d)列(1~%d)值:",i,M.mu,M.nu);scanf("%d%d%d",&m,&n,&e);k=0;if(m<1||m>M.mu||n<1||n>M.nu) //行或列超出围k=1;if(m<M.data[i-1].i||m==M.data[i-1].i&&n<M.data[i-1].j)k=1;}while(k);M.data[i].i=m;M.data[i].j=n;M.data[i].e=e;} //end forprintf("\n");return(OK);}void DestroySMatrix(RLSMatrix &M) //销毁稀疏矩阵M{M.mu=0;M.nu=0;M.tu=0;}void PrinRLSMatrix(RLSMatrix M) //遍历稀疏矩阵M{int i;printf("稀疏矩阵对应的三元组表为:\n\n");printf("行列元素值、\n\n");for(i=1;i<=M.tu;i++)printf("%2d%4d%8d\n",M.data[i].i,M.data[i].j,M.data[i].e);printf("\n\n");}void print(RLSMatrix A) //打印矩阵函数,以通常形式输出矩阵{int k=1,a,b;printf("稀疏矩阵的通常形式为:\n");int M[MAXSIZE][MAXSIZE];for(a=0;a<A.mu;a++) //初始化矩阵M{for(b=0;b<A.nu;b++)M[a][b]=0;}while(k<=A.tu){M[A.data[k].i-1][A.data[k].j-1]=A.data[k].e;k++;}for(a=0;a<A.mu;a++){printf(" | ");for(b=0;b<A.nu;b++)printf("%d ",M[a][b]);printf(" | \n");}}void showtip() //菜单{printf(" ********************请选择要执行的操作********************\n\n");printf(" & 1 采用一般算法实现&\n");printf(" & 2 采用快速转置的算法实现&\n");printf(" & 3 同时采用两种算法,先显示一般算法,再显示快速算法&\n");printf("**********************************************************\n\n");}////头文件结束TransposeSMatrix(RLSMatrix M,RLSMatrix &T) //求稀疏矩阵M的转置矩阵T(一般算法) {int p,q,col;T.mu=M.nu;T.nu=M.mu;T.tu=M.tu;if(T.tu){q=1;for(col=1;col<=M.nu;++col) //按列序求转置for(p=1;p<=M.tu;++p)if(M.data[p].j==col){T.data[q].i=M.data[p].j;T.data[q].j=M.data[p].i;T.data[q].e=M.data[p].e;++q;}}return OK;}FastTransposeSMatrix(RLSMatrix M,RLSMatrix &T) //快速转置算法{int p,q,t,col,*num,*cpot;num=(int*)malloc((M.nu+1)*sizeof(int));cpot=(int*)malloc((M.nu+1)*sizeof(int));T.mu=M.nu;T.nu=M.mu;T.tu=M.tu;if(T.tu){for(col=1;col<=M.nu;++col)num[col]=0;for(t=1;t<=M.tu;++t)++num[M.data[t].j];cpot[1]=1;for(col=2;col<=M.nu;++col)cpot[col]=cpot[col-1]+num[col-1];printf("\n辅助数组的值为:\n");printf("列号:");for(t=1;t<=M.nu;++t)printf("%4d",t);printf("\n");printf("num[]");for(t=1;t<=M.nu;++t)printf("%4d",num[t]);printf("\n");printf("cpot[]");for(t=1;t<=M.nu;++t)printf("%4d",cpot[t]);printf("\n\n");for(p=1;p<=M.tu;++p){col=M.data[p].j;q=cpot[col];T.data[q].i=M.data[p].j;T.data[q].j=M.data[p].i;T.data[q].e=M.data[p].e;++cpot[col];}}free(num);free(cpot);return OK;}void main(){int result;int j;RLSMatrix A,B;//************************************************COORD Co={0,0};DWORD Write;SetConsoleTitle("稀疏矩阵的转置\n");HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleTextAttribute(hOut,FOREGROUND_RED|FOREGROUND_BLUE|FOREG ROUND_INTENSITY);FillConsoleOutputAttribute(hOut,FOREGROUND_RED|FOREGROUND_BLUE|FORE GROUND_INTENSITY,100000000,Co,&Write);///windows的API函数,用来设置控制台标题do{showtip(); //调用菜单函数int i;scanf("%d",&i);switch(i){case 1:printf("创建矩阵A:");if((result=CreateSMatrix(A))==0)exit(ERROR);PrinRLSMatrix(A);printf("求A的转置矩阵B(一般算法):\n");TransposeSMatrix(A,B);PrinRLSMatrix(B);print(B);DestroySMatrix(B);printf("\n\n");break;case 2:printf("创建矩阵A:");if((result=CreateSMatrix(A))==0)exit(ERROR);PrinRLSMatrix(A);printf("求A的转置矩阵B(快速转置):\n");FastTransposeSMatrix(A,B);PrinRLSMatrix(B);print(B);DestroySMatrix(A);DestroySMatrix(B);printf("\n\n");break;case 3:printf("创建矩阵A:");if((result=CreateSMatrix(A))==0)exit(ERROR);PrinRLSMatrix(A);printf("求A的转置矩阵B------(一般算法):\n");TransposeSMatrix(A,B);PrinRLSMatrix(B);print(B);DestroySMatrix(B);printf("\n\n");printf("求A的转置矩阵B------(快速转置):\n");FastTransposeSMatrix(A,B);PrinRLSMatrix(B);print(B);DestroySMatrix(A);DestroySMatrix(B);printf("\n\n");break;}printf(" **********请选择是否继续输入其他稀疏矩阵?**********\n");printf(" 1 是,输入其他矩阵\n");printf(" 0 否,不输入\n");printf("****************************************************");fflush(stdin);//清除输入缓存区scanf("%d",&j);}while(j==1);}运行结果:(1)创建矩阵(2)一般转置(3)快速转置2、稀疏矩阵乘法、加法的算法(一般&十字链表)代码:#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){link p;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。