考点:广义表的长度和深度,稀疏矩阵的相关操作
广义表:LA=(A1,A2,…,An),LA为表名,n为表长,其中Ai可以是单个元素,亦可以是广义表,分别称为 原子和子表。A1为表头,(A2,…An)为表尾
1:广义表表长:原子的个数(此时要把最大子表广义归结为原子)
2:广义表深度:括弧的重数,空表深度为1
3:已知广义表A=((a,b,c),(d,e,f)),从表中取e的运算:
分解:tail(A)=((d,e,f)),head(tail(A))=(d,e,f),
tail(head(tail(A)))=(e,f),head(tail(head(tail(A))))=e
考的不多,代码就不写了呀
稀疏矩阵
1:定义:σ=tu /(mu*nu),σ<=0.05,tu为非零元个数,mu为行数,nu为列数
#define MAXSIZE 12500
#define MAXRC 500
#define Error -1
#define ok 0
#define N 5
#define a 4
#define b 5
#define c 3
typedef int Elemtype;
typedef int Status;
Elemtype i=0,j=0,e=0; //全局变量 为将来替换 a b c做准备
typedef struct {
int i,j;//行列下标
int e;
}Triple;//三元组结构体
typedef struct{
Triple data[MAXSIZE+1];
int rpos[MAXRC];/*用来保存第i行中第一个非0元在三元组的序号*/
int mu,nu,tu;//行号 列号的个数, 非0元个数
}RLMatrix;
//因为严蔚敏奶奶版的数组下标是从1开始的故而重设了行下标全为0的第一行和列下标=0第一列
Elemtype M[a][b]={{0,0,0,0,0},{0,3,0,0,5},{0,0,-1,0,0},{0,2,0,0,0}};
Elemtype NN[b][c]={{0,0,0},{0,0,2},{0,1,0},{0,-2,4},{0,0,0}};
//------------普通矩阵转换成三元组(同时还要建立rpos矩阵)----------------//
Status OrdinaryMatrix2RLMatrix(Elemtype Ordinary[i][j],RLMatrix *A){
int l=1,m=1,k=1;
(*A).mu=0;(*A).nu=0;(*A).tu=0;
//第0行第一个非0元的序号
for(l=1;l<i;l++)//统计行总数 不为空
{printf("\n");
(*A).mu=l;
(*A).rpos[l]=k; //第l行第一个非0元在三元组排列的序号
for(m=1;m<j;m++) {
(*A).nu=m;
if(Ordinary[l][m]!=0){
(*A).data[k].e=Ordinary[l][m];
(*A).data[k].i=l;//
(*A).data[k].j=m;
printf("该矩阵.data[%d].%d.%d=%d\n",k,(*A).data[k].i,(*A).data[k].j,(*A).data[k].e);
k++;
}
}
printf("rpos[%d]=%d\n",l,(*A).rpos[l]);
}
(*A).tu=k-1;
printf("A.mu=%d A.nu=%d A.tu=%d",(*A).mu,(*A).nu,(*A).tu);
return ok;
}
M Matrix的三元组表示
稀疏矩阵的乘法: rpos[]数组很重要
Status MultSMatrixTEST(RLMatrix *M,RLMatrix *N1,RLMatrix *Q){//Q=M*N
int tp=0,t=0,mrow=0,nrow=0,Qcol=0,p=0,q=0;
(*Q).rpos[a*c],Elemtype ctemp[a*c]={0};
if((*M).nu!=(*N1).mu) return Error; //不满足矩阵的乘法原则
for(mrow=1;mrow<=(*M).mu;mrow++){//找到每一行的非0元来做乘法
ctemp[mrow]=0;//设当前行的累加器清零 比如说一个行内有两个非0元 做矩阵乘法就需要先乘后加
(*Q).rpos[mrow]=(*Q).tu+1;//记录Q每一行第一个非0元在Q.data的位置
if(mrow<(*M).mu) tp=(*M).rpos[mrow+1];//1
else tp=(*M).tu+1;//2 (1,2,3)的作用是:(*M).rpos[mrow+1]-(*M).rpos[mrow]=找齐当前行非0元的个数
for(p=(*M).rpos[mrow];p<tp;p++){//3 for来遍历一行的每一个非零元
nrow=(*Q).data[p].j;//M的j等于N的i
if(nrow<(*N1).mu) t=(*N1).rpos[nrow+1];//1
else t=(*N1).tu+1;//2 1,2,3//找齐M的列对应在N的行号
for(q=(*N1).rpos[nrow];q<t;q++){//3 该列每一个非零元
Qcol=(*N1).data[q].j;//乘积元素在Q的列号
printf("Qcol=%d",Qcol);
ctemp[Qcol]+=(*M).data[p].e*(*N1).data[q].e;
printf("\nM.data[%d].%d.%d.%d*N1.data[%d].%d.%d.%d=ctemp[%d]=%d\n",p,(*M).data[p].i,(*M).data[p].j,(*M).data[p].e,q,(*N1).data[q].i,(*N1).data[q].j,(*N1).data[q].e,Qcol,ctemp[Qcol]);
}//for q
}//for p
printf("\n--------------分割线-----------\n");
for(Qcol=1;Qcol<=(*Q).nu;++Qcol){//save 该非0元
if(ctemp[Qcol]) {//总共就存在这么多个
if(++(*Q).tu>MAXSIZE) return Error;
(*Q).data[(*Q).tu].e=ctemp[Qcol];
(*Q).data[(*Q).tu].i=mrow;
(*Q).data[(*Q).tu].j=Qcol;
printf("Q.data[%d].%d.%d=%d\n",(*Q).tu,mrow,Qcol,(*Q).data[(*Q).tu].e);
}
}
}//for mrow
return ok;
}
void test(){
TSMatrix A;
TSMatrix T;
RLMatrix M1;
RLMatrix N1;
RLMatrix Q;
//
printf("NN矩阵如下:\n");
for(i=0;i<b;i++){
for(j=0;j<c;j++)
printf("%2d",NN[i][j]);
printf("\n");
}
OrdinaryMatrix2RLMatrix(NN,&N1);//M-->M1普通矩阵转化成三元组M1
printf("\nM矩阵如下:\n");
for(i=0;i<a;i++){
for(j=0;j<b;j++)
printf("%2d",M[i][j]);
printf("\n");
}
OrdinaryMatrix2RLMatrix(M,&M1);
// printf("\n--------------------Q-----------------\n");
MultSMatrixTEST(&M1,&N1,&Q);
}
矩阵加法不宜使用三元组结构,故而使用十字链表;为什么不宜呢?譬如把B三元组矩阵加入到A三元组矩阵,那么就会破坏A三元组矩阵的结构(A矩阵的0元在A三元组表示里面是没有位置的)
typedef struct OLNode{
int i,j;
Elemtype e;
struct OLNode *right ,*down;//该非0元所在行表和列表的后继链域
}OLNode,*OLink;//头结点,头指针
typedef struct{
OLink *chead,*rhead;//行和列链表 头指针向量基地址 由createSMatrix分配
int mu,nu,tu;//稀疏矩阵的行列非0元的总个数
}CrossList;
Status CreateSMatrix_OL(CrossList *M){//M只有行指针和列指针
int k=0;
i=1;
OLink p=NULL,q=NULL;//q是工具结点
p = (OLink) malloc (sizeof(OLNode));
q = (OLink) malloc (sizeof(OLNode)); //开辟内存
printf("\n输入M的行数,列数 非0元个数\n");
scanf("%d,%d,%d",&(M->mu),&(M->nu),&(M->tu));//M的行数,列数 非0元个数
printf("\ntesting");
M->rhead=(OLink *)malloc((M->mu+1)*sizeof(OLink));//开辟那么大的的内存
M->chead=(OLink *)malloc((M->nu+1)*sizeof(OLink));
for(k=1;k<=M->mu;k++)M->rhead[k]=NULL;//初始化行列头指针向量,各行列链表为
for(k=1;k<=M->nu;k++)M->chead[k]=NULL;
printf("\n输入行列非0元值:\n");
for(scanf("%d,%d,%d",&i,&j,&e);i!=0;scanf("%d,%d,%d",&i,&j,&e)){
printf("\n输入行列非0元值:\n");
if(!(p=(OLNode *)malloc(sizeof(OLNode)))) return Error;
p->i=i,p->j=j,p->e=e;
p->down=NULL,p->right=NULL;
if(M->rhead[i]==NULL||M->rhead[i]->j>j){//开头第一个 或者是同行的 但是前一个插入得比较右边
p->right=M->rhead[i];//先指向空
M->rhead[i]=p;//M的头指针指向p
}
else {
for(q=M->rhead[i];(q->right)&&q->right->j<j;q=q->right) ;//M->rhead[i]是上一个行指针所指结点 q->right是应到结点,q是上一结点 (向右攀爬)
p->right=q->right;
q->right=p;//p是新结点 q->right是指定位置
}
//--------down是用来处理行的,因为对于十字链表来说列已经确定了
if(M->chead[j]==NULL||M->chead[j]->i>i){//开头or同列 或者前一个比较下边
p->down=M->chead[j];//p->down 先指向空
M->chead[j]=p;//指向 新节点
}
else{
for(q=M->chead[j];(q->down)&&q->down->i<=i;q=q->down);//M->chead[i]是上一个列指针所指结点 q->down是应到结点,q是上一结点 (向下攀爬)
p->down=q->down;
q->down=p;//p是新结点 q->down是指定位置
}
}
}
Status RowVisitCrossList(CrossList *M){//用行来遍历十字链表
int i=0;OLNode *p=NULL;//定义结构体指针
p=(OLink)malloc(sizeof(OLNode)) ;
for(i=1;i<=M->mu;i++){
p=M->rhead[i];
while(p!=NULL){
printf("当前正在遍历第%d行第%d列的元素:%d\n",p->i,p->j,p->e);
p=p->right;
}
printf("\n");
}
}
Status ColVisitCrossList(CrossList *M){//用列来遍历十字链表
int j=0;
OLink p=NULL;
p=(OLNode *)malloc(sizeof(OLNode));///分配地址
for(j=1;j<=M->nu;j++){
p=M->chead[j];
while(p!=NULL){
printf("当前正在遍历第%d行第%d列的元素:%d\n",p->i,p->j,p->e);
p=p->down;
}
printf("\n");
}
}
Status MatrixAdd(CrossList *M,CrossList *S){//将M元素加入S里面
int i=0;OLNode *p=NULL,*q=NULL;//定义结构体指针
p=(OLink)malloc(sizeof(OLNode)) ;
q=(OLink)malloc(sizeof(OLNode)) ;
for(i=1;i<=M->mu;i++){//行遍历那就 用列来做加法
p=M->rhead[i];
while(p!=NULL){
printf("当前正在遍历M的第%d行第%d列的元素:%d\n",p->i,p->j,p->e);
printf("S->rhead[p->i]->i=%d,S->chead[p->j]->j=%d\n",S->rhead[p->i]->i,S->chead[p->j]->j);
if(S->rhead[p->i]->i==p->i&&S->chead[p->j]->j==p->j){
for(q=S->chead[p->j];(q->down)&&q->down->i<=p->i;q=q->down);
q->e+=p->e;///主要解决指针不下移动问题 chead[p->j]andq->down->i<=p->i
printf("AllADD\n");
}
else{
if(S->rhead[p->i]==NULL||S->rhead[p->i]->j>p->j){//开头第一个 或者是同行的 但是前一个插入得比较右边
p->right=M->rhead[i];//先指向空 或者指向先前比较右边的那个
S->rhead[p->i]=p;//M的头指针指向p
}
else {//按正常顺序 左边--》右边
for(q=M->rhead[p->i];(q->right)&&q->right->j<p->j;q=q->right) ;//M->rhead[i]是上一个行指针所指结点 q->right是应到结点,q是上一结点 (向右攀爬)
p->right=q->right;//此时是q->right为NULL 让新的结点右域指向空
q->right=p;//p是新结点 q->right是指定位置(结点连接)
}
//--------down是用来处理行的,因为对于十字链表来说列已经确定了
if(S->chead[p->j]==NULL||S->chead[p->j]->i>p->i){//开头or同列 或者前一个比较下边
p->down=S->chead[p->j];//p->down 先指向空 或者指向先前(比较下的)那个
S->chead[p->j]=p;//指向 新节点
}
else{
for(q=S->chead[p->j];(q->down)&&q->down->i<=p->i;q=q->down);//S->chead[i]是上一个列指针所指结点 q->down是应到结点,q是上一结点 (向下攀爬)
p->down=q->down;//新结点指向空
q->down=p;//p是新结点 q->down是指定位置(结点连接)
}
}
p=p->right;
printf("\n");
}
}
}
void test(){
CrossList M;
CrossList S;
CreateSMatrix_OL(&M);
CreateSMatrix_OL(&S);
printf("\n--------------M的元素如下-----------\n");
ColVisitCrossList(&M);
printf("\n--------------S的元素如下-----------\n");
ColVisitCrossList(&S);
printf("\n------------------------------------\n");
MatrixAdd(&M,&S);
printf("\n----------下面遍历改变后的S----------\n");
RowVisitCrossList(&S);
}