数据结构组广义表共79页文档
数据结构课程chap05数组和广义表
基本操作:
InitArray(&A, n, bound1, ..., boundn) DestroyArray(&A) Value(A, &e, index1, ..., indexn) Assign(&A, e, index1, ..., indexn)
InitArray(&A, n, bound1, ..., boundn)
①-④: A.12 B. 66 C. 72 D. 96 E. 114 F. 120
G. 156 H. 234 I. 276 J. 282 K. 283 L. 288
⑤: A.行与列的上界相同
B. 行与列的下界相同
C. 行与列的上、下界都相同 D. 行的元素个数与列的元素个 数相同
LJCIC
练习
一n×n的三角矩阵A=[aij]如下:
R={R1, R2, ..., Rn} Ri={<a , a > | j1,... ji,... jn j1, ...ji +1, ...jn 0 jk bk -1, 1 k n 且k i, 0 ji bi -2, i=2,...,n } 基本操作:
} ADT Array
1) 零值元素占了很大空间; 2) 计算中进行了很多和零值的运算,
遇除法,还需判别除数是否为零。
解决问题的原则:
1) 尽可能少存或不存零值元素;
2) 尽可能减少没有实际意义的运算;
3) 操作方便。 即: 能尽可能快地找到与
下标值(i,j)对应的元素, 能尽可能快地找到同
一行或同一列的非零值元。
有两类稀疏矩阵:
1) 特殊矩阵 非零元在矩阵中的分布有一定规则
例如: 三角矩阵 对角矩阵
数据结构数组与广义表
/*稀疏矩阵转置:经典算法,二维数组存储方式*/#include<stdio.h>#include<stdlib.h>#define m6#define n7typedef int ElementType;/*算法5.1稀疏矩阵转置经典算法*/void TransMatrix(ElementType source[m][n],ElementType dest[n][m]){ int i,j;for(i=0;i<m;i++)for(j=0;j<n;j++)dest[j][i]=source[i][j];}/*T(n)=O(m*n),形参的S(n)=O(m*n)*/int main(void){int i,j;/*二维数组存储稀疏矩阵,初始化source矩阵*/ElementType source[m][n]={{0,12,9,0,0,0,0},{0,0,0,0,0,0,0},{-3,0,0,0,0,14,0},{0,0,24,0,0,0,0},{0,18,0,0,0,0,0},{15,0,0,-7,0,0,0}},dest[n][m];TransMatrix(source,dest);printf("被转置的矩阵:\n");for(i=0;i<m;i++){for(j=0;j<n;j++)printf("%4d",source[i][j]);printf("\n");}printf("转置后的矩阵:\n");for(i=0;i<n;i++){for(j=0;j<m;j++)printf("%4d",dest[i][j]);printf("\n");}return0;}/*稀疏矩阵转置:行列互换转置算法,三元组表存储方式*/#include<stdio.h>#include<stdlib.h>typedef int ElementType;#define MAXSIZE1000/*三元组表结点类型定义*/typedef struct{int row,col;/*行号、列号*/ElementType e;/*元素值*/}Triple;/*三元组表类型的定义*/typedef struct{Triple data[MAXSIZE+1];/*顺序表*/int m,n,len;/*行数、列数、非零元素个数*/}TSMatrix;/*稀疏矩阵行列互换转置算法*/void TransposeMatrix(TSMatrix A,TSMatrix*B){int i,j,k,p;Triple temp;/*临时结点*//*新的行数、列数、非零元素个数确定*/B->m=A.n;B->n=A.m;B->len=A.len;/*存在非零结点*/if(B->len>0){/*行列互换*/for(i=1;i<=A.len;i++){B->data[i].row=A.data[i].col;B->data[i].col=A.data[i].row;B->data[i].e=A.data[i].e;}/*三元组表B按行号排序,注意同号的次序不能打乱,不能用一般的排序方法*/k=1;/*B中将要确定的结点下标*/for(i=1;i<=B->m;i++)/*遍历每个行号,行号从1--b->m*/for(j=k;j<=B->len;j++)/*B中k-1以前的已处理*/if(i==B->data[j].row){/*找到结点*/temp=B->data[j];/*把找到的结点暂存*/for(p=j;p>k;p--)/*向后移动元素,空出位置k*/B->data[p]=B->data[p-1];B->data[k++]=temp;/*确定第k个结点,准备下一结点下标*/ }}}/*行列交换T(n)=O(A.len)最坏移动元素的次数:A.len(A.len-1)/2*/int main(void){int i,j,k;/*定义三元组表A、B,并初始化A*/TSMatrix A={0,0,0,/*0下标不结点使用*/1,2,12,1,3,9,3,1,-3,3,6,14,4,3,24,5,2,18,6,1,15,6,4,-7},B;A.m=6;A.n=7;A.len=8;/*调用函数实现转置*/TransposeMatrix(A,&B);/*输出三元组形式*/printf("三元组表A:\n");for(i=1;i<=A.len;i++)printf("%4d%4d%4d\n",A.data[i].row,A.data[i].col,A.data[i].e);printf("三元组表B:\n");for(i=1;i<=B.len;i++)printf("%4d%4d%4d\n",B.data[i].row,B.data[i].col,B.data[i].e);/*输出矩阵形式*/printf("三元组表A表示的稀疏矩阵:\n");k=1;/*三元组表的结点下标*/for(i=1;i<=A.m;i++){for(j=1;j<=A.n;j++)if(A.data[k].row==i&&A.data[k].col==j){printf("%4d",A.data[k].e);k++;}elseprintf("%4d",0);printf("\n");}printf("三元组表B表示的稀疏矩阵:\n");k=1;for(i=1;i<=B.m;i++){for(j=1;j<=B.n;j++)if(B.data[k].row==i&&B.data[k].col==j){printf("%4d",B.data[k].e);k++;}elseprintf("%4d",0);printf("\n");}return0;}/*稀疏矩阵转置:列序递增转置算法,三元组表存储方式*/ #include<stdio.h>#include<stdlib.h>typedef int ElementType;#define MAXSIZE1000/*三元组表结点类型定义*/typedef struct{int row,col;/*行号、列号*/ElementType e;/*元素值*/}Triple;/*三元组表类型的定义*/typedef struct{Triple data[MAXSIZE+1];/*顺序表*/int m,n,len;/*行数、列数、非零元素个数*/}TSMatrix;/*算法5.2稀疏矩阵列序递增转置算法*/void TransposeMatrix(TSMatrix A,TSMatrix*B){/*i--A的结点下标,j--B的结点下标,k--A的列序号*/int i,j,k;/*新的行数、列数、非零元素个数确定*/B->m=A.n;B->n=A.m;B->len=A.len;/*存在非零结点*/if(B->len>0){j=1;/*B的结点下标j从1开始*/for(k=1;k<=A.n;k++)/*列序递增:1--A.n*/for(i=1;i<=A.len;i++)/*每个列号k,扫描三元组表A的所有元素*/ if(k==A.data[i].col){/*找到了*/B->data[j].row=A.data[i].col;B->data[j].col=A.data[i].row;B->data[j].e=A.data[i].e;j++;/*B的下一个结点下标*/}}}/*T(n)=O(A.n*A.len)*/int main(void){int i,j,k;/*定义三元组表A、B,并初始化A*/TSMatrix A={0,0,0,/*0下标不结点使用*/1,2,12,1,3,9,3,1,-3,3,6,14,4,3,24,5,2,18,6,1,15,6,4,-7},B;A.m=6;A.n=7;A.len=8;/*调用函数实现转置*/TransposeMatrix(A,&B);/*输出三元组形式*/printf("三元组表A:\n");for(i=1;i<=A.len;i++)printf("%4d%4d%4d\n",A.data[i].row,A.data[i].col,A.data[i].e);printf("三元组表B:\n");for(i=1;i<=B.len;i++)printf("%4d%4d%4d\n",B.data[i].row,B.data[i].col,B.data[i].e);/*输出矩阵形式*/printf("三元组表A表示的稀疏矩阵:\n");k=1;/*三元组表的结点下标*/for(i=1;i<=A.m;i++){for(j=1;j<=A.n;j++)if(A.data[k].row==i&&A.data[k].col==j){printf("%4d",A.data[k].e);k++;}elseprintf("%4d",0);printf("\n");}printf("三元组表B表示的稀疏矩阵:\n");k=1;for(i=1;i<=B.m;i++){for(j=1;j<=B.n;j++)if(B.data[k].row==i&&B.data[k].col==j){printf("%4d",B.data[k].e);k++;}elseprintf("%4d",0);printf("\n");}return0;}/*稀疏矩阵转置:一次定位快速转置算法,三元组表存储方式*/ #include<stdio.h>#include<stdlib.h>typedef int ElementType;#define MAXSIZE1000/*三元组定义*/typedef struct{int row,col;/*行号、列号*/ElementType e;/*元素值*/}Triple;/*三元组表定义*/typedef struct{Triple data[MAXSIZE+1];/*顺序表*/int m,n,len;/*行数、列数、非零元素个数*/}TSMatrix;/*算法5.3稀疏矩阵一次定位快速转置算法*/void FastTransposeMatrix(TSMatrix A,TSMatrix*B){/*col--A的列号、B的行号,p--A的结点下标,q--B的结点下标*/int col,p,q;/*定义数组num[A.n+1],用于分别存储每列的非零元素个数*/int*num=(int*)malloc(sizeof(int)*(A.n+1));/*定义数组position[A.n+1],第col列第一个非零元素在B中的位置下标*/ int*position=(int*)malloc(sizeof(int)*(A.n+1));/*新的行数、列数、非零元素个数确定*/B->m=A.n;B->n=A.m;B->len=A.len;/*存在非零结点*/if(B->len>0){/*每列非零元素个数初始化为0*/for(col=1;col<=A.n;col++)num[col]=0;/*统计每列中非零元素的个数*/for(p=1;p<=A.len;p++)num[A.data[p].col]++;/*设置position[1]的值为1,第1列第一个非零元素在B的位置为1*/position[1]=1;/*确定第col列第一个非零元素在B的位置*/for(col=2;col<=A.n;col++)position[col]=position[col-1]+num[col-1];/*将被转置矩阵的三元组表A从头至尾扫描一次,实现矩阵转置*/for(p=1;p<=A.len;p++){col=A.data[p].col;/*所在列号*/q=position[col];/*在B存放的位置*/B->data[q].row=A.data[p].col;/*交换*/B->data[q].col=A.data[p].row;B->data[q].e=A.data[p].e;position[col]++;/*col列的下一个非零元素在B的位置*/ }}}/*f(n)=A.n+A.len+1+(A.n-1)+A.len=2(A.n+A.len),即T(n)=O(A.n+A.len)*/ /*S(n)=A.n+1+A.n+1=2(A.n+1),即S(n)=O(A.n)*/int main(void){int i,j,k;/*定义三元组表A、B,并初始化A*/TSMatrix A={0,0,0,/*0下标不结点使用*/1,2,12,1,3,9,3,1,-3,3,6,14,4,3,24,5,2,18,6,1,15,6,4,-7},B;A.m=6;A.n=7;A.len=8;/*调用函数实现转置*/FastTransposeMatrix(A,&B);/*输出三元组形式*/printf("三元组表A:\n");for(i=1;i<=A.len;i++)printf("%4d%4d%4d\n",A.data[i].row,A.data[i].col,A.data[i].e);printf("三元组表B:\n");for(i=1;i<=B.len;i++)printf("%4d%4d%4d\n",B.data[i].row,B.data[i].col,B.data[i].e);/*输出矩阵形式*/printf("三元组表A表示的稀疏矩阵:\n");k=1;/*三元组表的结点下标*/for(i=1;i<=A.m;i++){for(j=1;j<=A.n;j++)if(A.data[k].row==i&&A.data[k].col==j){printf("%4d",A.data[k].e);k++;}elseprintf("%4d",0);printf("\n");}printf("三元组表B表示的稀疏矩阵:\n");k=1;for(i=1;i<=B.m;i++){for(j=1;j<=B.n;j++)if(B.data[k].row==i&&B.data[k].col==j){printf("%4d",B.data[k].e);k++;}elseprintf("%4d",0);printf("\n");}return0;}/*稀疏矩阵转置:一次定位快速转置算法,三元组表存储方式*/#include<stdio.h>#include<stdlib.h>typedef int ElementType;/*十字链表的类型定义*//*非零元素结点的定义*/typedef struct OLNode{int row,col;/*非零元素:行号、列号、值*/ElementType value;struct OLNode*right;/*行后继链域、列后继链域*/struct OLNode*down;}OLNode,*OLink;/*OLNode结点类型、OLink指向结点的指针类型*//*十字链表的定义*/typedef struct{OLink*row_head;/*行头指针向量,二重指针,指向第0个行链指针*/ OLink*col_head;/*列头指针向量,二重指针,指向第0个列链指针*/ int m,n,len;/*稀疏矩阵的行数、列数、非零元素的个数*/}CrossList;/*十字链表类型*//*算法5.4创建十字链表*/void CreateCrossList(CrossList*M){int m,n,t;/*接收行数、列数、个数*/OLNode*p,*q;/*p指向新结点*/int i,j,e;/*接收结点的行号、列号、值*//*确定十字链表的成员m、n、len的值*/printf("输入M的行数、列数、非零元素的个数:\n");scanf("%d%d%d",&m,&n,&t);/*输入M的行数,列数和非零元素的个数*/ M->m=m;M->n=n;M->len=t;/*申请行列链指针分量,并确定row_head、col_head的值*//*申请m+1个行链指针分量,m+1个行链表*/if(!(M->row_head=(OLink*)malloc((m+1)*sizeof(OLink))))printf("error");/*申请n+1个列链指针分量,n+1个列链表*/if(!(M->col_head=(OLink*)malloc((n+1)*sizeof(OLink))))printf("error");/*把所有行列链指针置空*/for(i=1;i<=m;i++){M->row_head[i]=NULL;}for(i=1;i<=n;i++){M->col_head[i]=NULL;}/*链入结点*/printf("请输入非零结点行号、列号、值:(行号为0则结束输入)\n");for(scanf("%d%d%d",&i,&j,&e);i!=0;scanf("%d%d%d",&i,&j,&e)){ /*生成新结点*/if(!(p=(OLNode*)malloc(sizeof(OLNode))))printf("error");p->row=i;p->col=j;p->value=e;/*链入i行*/if(M->row_head[i]==NULL){/*是行中的第1个结点*/p->right=M->row_head[i];/*新结点尾置空*/M->row_head[i]=p;/*链接新结点*/}else{/*把q定位在第i行的未结点,利用空循环*/for(q=M->row_head[i];q->right&&q->right->col<j;q=q->right);p->right=q->right;/*新结点尾置空*/q->right=p;/*链接新结点*/}/*链入j列*/if(M->col_head[j]==NULL){/*是列中的第1个结点*/p->down=M->col_head[j];/*新结点尾置空*/M->col_head[j]=p;/*链接新结点*/}else{/*把q定位在第j行的未结点,利用空循环*/for(q=M->col_head[j];q->down&&q->down->row<i;q=q->down);p->down=q->down;/*新结点尾置空*/q->down=p;/*链接新结点*/}}}/*输出十字链表1*/void PrintCrossList(CrossList*M){int i,j;OLNode*p;for(i=1;i<=M->m;i++){/*以行为主输出*/p=M->row_head[i];/*行链起点*/for(j=1;j<=M->n;j++){if(p&&p->col==j){/*p存在且位于j列*/printf("%4d",p->value);p=p->right;/*链表下滑,不回溯*/}elseprintf("%4d",0);}printf("\n");}}/*输出十字链表2*/void out_Matrix(CrossList*M){int i,j;OLNode*p;for(i=1;i<=M->m;i++){/*以行为主输出*/for(j=1;j<=M->n;j++){p=M->row_head[i];/*每次均从本行头指针开始,p回溯*/while(p!=NULL){if(p->col==j)break;/*找到结点*/p=p->right;}if(p!=NULL)/*输出结点*/printf("%4d",p->value);elseprintf("%4d",0);}printf("\n");/*换行*/}}int main(void){CrossList M;CreateCrossList(&M);PrintCrossList(&M);out_Matrix(&M);return0;}/*广义表的头尾链表:头尾即表头、表尾的意思*/#include<stdio.h>#include<stdlib.h>#define AutoType int/*原子结点类型*//*结点分类:用枚举类型实现*/typedef enum{ATOM,LIST/*枚举值:值ATOM表示原子结点,值LIST表示子表*/ }ElemTag;/*ElemTag类型的变量仅有两个可取的枚举值*//*广义表结点类型的定义,广义表类型的定义*/typedef struct GLNOde{ElemTag tag;/*标志位tag用来区分原子结点和表结点*//*通过共用体实现广义表结点:要么是原子结点、要么是表结点*/ union{AutoType atom;struct{struct GLNode*hp,*tp;}htp;}atom_htp;}GLNode,*GList;int main(void){return0;}/*二维数组是“数据元素为一维数组”的线性表*//*即元素的类型是一种数据结构*/#include<stdio.h>#include<stdlib.h>#define M3#define N4#define ElementType int/*一维数组类型定义*/typedef struct{ElementType data[N];/*N个数据元素为ElementType的顺序表*/ }Array;/*新的数据类型为Array*/int main(void){Array A[M];/*M个数据类型为Array的顺序表*/int i,j;/*随机输入矩阵的值*/for(i=0;i<M;i++)for(j=0;j<N;j++)A[i].data[j]=rand()%100;/*范围0--99*//*输出矩阵的值*/for(i=0;i<M;i++){for(j=0;j<N;j++)printf("%4d",A[i].data[j]);printf("\n");}return0;}/*一维数组的顺序存储*/#include<stdio.h>#include<stdlib.h>int main(void){int a[10];/*顺序存储*/printf("a[0]的地址:%d\n",&a[0]);printf("a[5]的地址(内部实现):%d\n",&a[5]);/*Loc(a[i])=Loc(a[0])+(i-0)*size*//*Loc(a[i])=Loc(a[0])+(i)*size*//*size自动分配,例如+5,地址实质上增大了20*/printf("a[5]的地址(公式计算):%d\n",&a[0]+5);return0;}/*二维数组的顺序存储*/#include<stdio.h>#include<stdlib.h>int main(void){int a[5][4];/*以行为主的顺序存储,m=5行n=4列*/printf("a[0][0]的地址:%d\n",&a[0][0]);printf("a[3][2]的地址(内部实现):%d\n",&a[3][2]);/*Loc(a[i][j])=Loc(a[0][0])+((i-0)*n+(j-0))*size*//*Loc(a[i][j])=Loc(a[0][0])+(i*n+j)*size*/printf("a[3][2]的地址(公式计算):%d\n",&a[0][0]+3*4+2);return0;}/*三维数组的顺序存储*/#include<stdio.h>#include<stdlib.h>int main(void){int a[5][4][6];/*以行为主的顺序存储,m=5行n=4列r=6纵*/printf("a[0][0][0]的地址:%d\n",&a[0][0][0]);printf("a[3][2][4]的地址(内部实现):%d\n",&a[3][2][4]);/*Loc(a[i][j][k])=Loc(a[0][0][0])+((i-0)*n*r+(j-0)*r+(k-1))*size*//*Loc(a[i][j][k])=Loc(a[0][0][0])+(i*n*r+j*r+k)*size*/printf("a[3][2][4]]的地址(公式计算):%d\n",&a[0][0][0]+3*4*6+2*6+4);return0;}/*三角矩阵的压缩存储*/#include<stdio.h>#include<stdlib.h>#define ElementType int#define MAXSIZE1000/*矩阵的压缩类型定义*/typedef struct{ElementType data[MAXSIZE+1];/*非0元素的空间,data[0]未用*/int n,len;/*n为矩阵的阶数,即n*n矩阵;len非0元素的个数*/ }Matrix;int main(void){int i,j;/*下三角矩阵变量A的定义及初始化*/Matrix A={0,/*未用*/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};A.n=5;/*阶数n*/A.len=A.n*(A.n+1)/2;/*输出下三角矩阵*/for(i=1;i<=A.n;i++){for(j=1;j<=A.n;j++)if(i<j)printf("%4d",0);else/*下标从1考虑,第几个元素的下标就是几*/printf("%4d",A.data[i*(i-1)/2+j]);printf("\n");}return0;}/*三对角带状矩阵的压缩存储*/#include<stdio.h>#include<stdlib.h>#define ElementType int#define MAXSIZE1000/*矩阵的压缩类型定义*/typedef struct{ElementType data[MAXSIZE+1];/*非0元素的空间,data[0]未用*/int n,len;/*n为矩阵的阶数,即n*n矩阵;len非0元素的个数*/ }Matrix;int main(void){int i,j;/*三对角带状矩阵变量A的定义及初始化*/Matrix A={0,/*未用*/1,2,2,3,4,3,4,5,4,5,6,5,6};A.n=5;/*阶数n*/A.len=3*A.n-2;/*输出三对角带状矩阵*/for(i=1;i<=A.n;i++){for(j=1;j<=A.n;j++)if(j==i-1||j==i||j==i+1)/*三对角带状条件*/printf("%4d",A.data[2*(i-1)+j]);elseprintf("%4d",0);printf("\n");}return0;}。
数据结构-第五章 数组与广义表-文档资料
上 三 角 矩 阵 下 三 角 矩 阵
a00 a10 a 20 an10
0 1 2
a01 a11 a21 an11
3 4
a02 a12 a22 an12
5
6 7
a0 n1 a1n1 a2 n1 an1n1
行 列 值 (row) (col) (value) 0 4 91 1 1 11 2 5 28 3 0 22 3 2 -6 5 1 17 5 3 39 6 0 16
用三元组表表示的稀疏矩阵及其转置
行 列 值 (row) (col) (value) 0 3 22 0 6 15 1 1 11 1 5 17 2 3 -6 3 5 39 4 0 91 5 2 28 行 列 值 (row) (col) (value) 0 4 91 1 1 11 2 5 28 3 0 22 3 2 -6 5 1 17 5 3 39 6 0 16
4 5 6 7 8 9 10
B a00 a01 a10 a11 a12 a21 a22 a23 … an-1n-2 an-1n-1
三对角矩阵中除主对角线及在主对角线上 下最临 近的两条对角线上的元素外,所有其它元素均为 0。总共有3n-2个非零元素。 将三对角矩阵A中三条对角线上的元素按行存放在 一维数组 B 中,且a00存放于B[0]。 在三条对角线上的元素aij 满足 0 i n-1, i-1 j i+1 在一维数组 B 中 A[i][j] 在第 i 行,它前面有 3*i-1 个非零元素, 在本行中第 j 列前面有 j-i+1 个,所 以元素 A[i][j] 在 B 中位置为 k = 2*i + j。
三对角矩阵的压缩存储
数据结构讲稿课件-第4章串、数组和广义表
大学复习资料
专 业: 班 级: 科目老师: 日 期:
• 第2章 线性表
• 第3章 栈和队列
• 第4章 串、数组和广 义表
线性结构
可表示为:(a1 , a2 , ……, an)
2021/3/182021年3月21日
补充:C语言中常用的串运算 调用标准库函数 #include<string.h>
串比较,strcmp(char s1,char s2) 串复制,strcpy(char to,char from) 串连接,strcat(char to,char from) 求串长,strlen(char s)
……
2021/3/182021年3月21日
第4章 串、数组和广义表
教学内容
4.1 串 4.2 数组 4.3 广义表
i
BF算法设计思想
S :ababcabcacbab
•
T :abc j
i指针回溯
S :ababcabcacbab
T : abc
S :ababcabcacba b
T : abc
BF算法设计思想
Index(S,T,pos)
• 将主串的第pos个字符和模式的第一个字符比较, 若相等,继续逐个比较后续字符; 若不等,从主串的下一字符起,重新与模式的第 一个字符比较。
• 直到主串的一个连续子串字符序列与模式相等 。 返回值为S中与T匹配的子序列第一个字符的序号, 即匹配成功。
• 否则,匹配失败,返回值 0
BF算法描述(算法4.1)
int Index(Sstring S,Sstring T,int pos){ i=pos; j=1; while (i<=S[ 0 ] && j <=T[ 0 ]){ if ( S[ i ]=T[ j ]) {++i; ++j; } else{ i=i-j+2; j=1; } if ( j>T[ 0 ]) return i-T[0]; else return 0;
数据结构组广义表
基本操作:
InitArray(&A, n, bound1, ..., boundn)
DestroyArray(&A) Value(A, &e, index1, ..., indexn) Assign(&A, e, index1, ..., indexn)
InitArray(&A, n, bound1, ..., boundn) 操作结果:若维数 n 和各维长度合法, 则构造相应的数组A,并 返回OK。
(数组)提要
5.1.1 数组的类型定义 5.1.2 数组的顺序表示和实现
5.1.3 矩阵的压缩存储
ADT Array { 数据对象: D={aj1,j2, ..., jn| ji =0,...,bi -1, i=1,2,..,n (n>0), aj1,j2, ..., jn ∈ElemSet}
数据关系:
} }// transposeSMatrix 算法的时间复杂度:O(nu×tu)
用常规的二维数组表示时的算法:
for (col=1; col<=nu; ++col) for (row=1; row<=mu; ++row) T[col][row] = M[row][col];
其时间复杂度为: O(mu×nu)
0
0
0
0
0
0
以常规方法,即以二维数组表示高阶 的稀疏矩阵时会产生的问题:
1) 零值元素占了很大空间; 2) 计算中进行了很多和零值的运算, 遇除法,还需判别除数是否为零。
解决问题的原则:
1) 尽可能少存或不 即:
尽可能快地找到与下标值(i,j)对应的元素, 尽可能快地找到同一行或同一列的非零元素。
数据结构-广义表
数据结构-⼴义表⼴义表简称表,是线性表的推⼴,表中元素可以是数据元素(原⼦),也可以是⼦表。
⼴义表的表头(head)是表中第⼀个表元素、表尾(tail)是除了表头外其它元素组成的表。
⾸先要对⼴义表结点类GenListNode和返还值的结构类Item进⾏定义。
它们都有⼀个⽤来标明结点类型的标志域utype、⼀个信息域info。
此外,⼴义表结点类还多了⼀个尾指针tlink指向下⼀个结点。
utype为0时为⼴义表专⽤的附加头结点,info存放引⽤计数refutype为1时为原⼦结点、info存放数据值valueutype为2时为⼦表结点,info存放指向⼦表表头的指针hlink这种存储表⽰中,⼴义表中的所有表,⽆论是哪⼀层的⼦表,都带有⼀个附加头结点,空表也不例外所有位于同⼀层的表元素,在其存储表⽰中也在同⼀层最⾼⼀层的表结点个数(除附加头结点外)即为表的长度#include <iostream>#include <assert.h>#include <stdlib.h>using namespace std;template <class T>struct Items{ //返回值的类结构定义int utype; //标志域union{int ref; //utype=0,存放引⽤计数T value; //utype=1,存放数值GenListNode<T> *hlink; //utype=2.存放指向⼦表的指针} info;Items():utype(0),info.ref(0){} //构造函数Items(Items<T>& RL){utype=RL.utype;info=;} //复制构造函数}template <class T>struct GenListNode{ //⼴义表结点类定义public:GenListNode():utype(0),tlink(NULL),info.ref(0){}GenListNode(GenListNode<T>& RL){utype=RL.utype;tlink=Rl.tlink;info=;}private:int utype;GenListNode<T> *tlink; //⽐返回值的类结构多了⼀个tlink指针union{int ref;T value;GenListNode<T> *tlink;} info;}template <class T>class Genlist{public:Genlist();~Genlist();bool Head(Items& x);bool Tail(Genlist<T>& It);GenListNode<T> *First();GenListNode<T> *Next(GenListNode<T> *elem);void Copy(const Genlist<T>& R);int Length();int depth();friend istream& operator>>(istream& in,Genlist<T>& L);private:GenListNode<T> *first; //⼴义表头指针GenListNode<T> *Copy(GenListNode<T> *ls);int Length(GenListNode<T> *ls);int depth(GenListNode<T> *ls);bool equal(GenListNode<T> *s,GenListNode<T> *t); //判断s和t为表头的两个表是否相等void Remove(GenListNode<T> *ls);void Createlist(istream& in,GenListNode<T> *&ls);}template <class T>Genlist<T>::Genlist(){ //构造函数first=new GenlistNode;assert(first!=NULL);}//Head⽅法返回bool值,通过引⽤变量x返回是⼴义表第⼀个元素(Item类型的对象);template <class T>bool Genlist<T>::Head(Items<T>& x){//若⼴义表⾮空,则通过x返回其第⼀个元素的值,否则函数没有意义if(first->tlink==NULL) return false;else{x.utype=first->tlink->utype;=first->tlink->info;return true;}}template <class T>bool Genlist<T>::Tail(Genlist<T>& It){//若⼴义表⾮空,则通过It返回⼴义表除表头元素以外其他元素组成的表,否则函数没有意义if(first->tlink==NULL) return false;else{It.first->utype=0;It.first->info.ref=0;It.first->tlink=Copy(first->tlink->tlink);return true;}}//First⽅法返回的是指向⼴义表第⼀个元素(GenlistNode类型的对象)的指针template <class T>GenlistNode<T> *Genlist<T>::First(){if(first->tlink==NULL)return NULL;else return first->tlink;}template <class T>GenlistNode<T> *Genlist<T>::Next(GenlistNode<T> *elem){ //返回表元素elem的直接后继元素if(elem->tlink==NULL) return NULL;else return elem->tlink;}⼴义表的遍历可以⽤如下⽅法:template <class T>struct Items {int mark;int utype;union{char *LName; //附加头结点的info域改为了表名T value;GenListNode<T> *hlink;}info;Items():mark(0),utype(0),info.LName('\0'){}Items(Items<T>& RL){mark=Rl.mark;utype=RL.utypr;info=;}}template <class T>struct GenListNode {public:GenListNode():mark(0),utype(0),tlink(NULL),info.LName('\0'){}GenListNode(GenListNode<T>& RL){mark=RL.mark; utype=RL.utype; tlink=RL.tlink; info=;} int getMark(GenListNode<T> *elem){return elem->mark;}int getType(GenListNode<T> *elem){return elem->utype;}int getListName(GenListNode<T> *elem){return elem->info.LName;}T getValue(GenListNode<T>* elem){return elem->info.value;}GenListNode* gettlink(GenListNode<T>* elem){return elem->tlink;}GenListNode* gethlink(GenListNode<T>* elem){return elem->info.hlink;}private:int mark;int utype;GenListNode<T> *tlink;union{char *LName;T value;GenListNode<T> *hlink;}info;}template GenList{public:GenList();~GenList(){Remove(first);}bool Head(Items& x);bool Tail(GenList<T> <);GenListNode<T> *First(){return first;}GenListNode<T> *Next(GenListNode<T> *elem){return elem->tlink;} void Traverse(); //⾮递归遍历private:GenListNode<T> *first;void Traverse(GenListNode<T> *ls); //递归遍历}template <class T>void GenList::Traverse(){Stack<GenListNode<T>*> st;GenListNode<T> *ls=first;while (ls!=NULL) {ls->mark=1;if (ls->utype==2){ //⼦表结点if (ls->info.hlink->mark==0){st.Push(ls->tlink;) //暂时先把⼦表结点的右结点⼊栈ls=ls->hlink;}else { //⼦表已经遍历过cout<<ls->info.hlink->info.LName;if(ls->tlink!=NULL){cout<<',';ls=ls->tlink;}}}else {if (ls->utype==0) cout<<ls->info.LName<<'('; //表头结点else if (ls->utype==1){ //原⼦结点cout<<ls->info.value;if(ls->tlink!=NULL) cout<<',';}if(ls->tlink==NULL){cout<<')';if(!st.isEmpty()){st.Pop(ls);if(ls!=NULL) cout<<',';else cout<<')';}}else ls=ls->tlink;}}}template <class T>void GenList::Traverse(GenListNode<T> *ls){if(ls!=NULL){ls->mark=1;if (ls->utype==0) cout<<ls->info.LName<<'('; //表头结点else if (ls->utype==1) { //原⼦结点cout<<ls->info.value;if (ls->tlink!=NULL) cout<<',';}else if (ls->utype==2) { //⼦表结点if (ls->info.hlink->mark==0) Traverse(ls->info.hlink);else cout<<ls->info.hlink->info.LName; //⼦表已经遍历过if (ls->tlink!=NULL) cout<<',';}Traverse(ls->tlink);}else cout<<')';}。
数据结构广义表
{ printf("("); /*输出'('*/
if (g->val.sublist==NULL) printf(""); /*输出空子表*/
else DispGL(g->val.sublist); /*递归输出子表*/
}
else printf("%c", g->val.data); /*为原子时输出元素值*/
假如把每个表旳名字(若有旳话)写在其表旳前面,则 上面旳5个广义表可相应地体现如下:
A()
B(e)
C(a,(b,c,d))
D(A(),B(e),C(a,(b,c,d)))
E((a,(a,b),((a,b),c)))
若用圆圈和方框分别体现表和单元素,并用线段把表 和它旳元素(元素结点应在其表结点旳下方)连接起来,则 可得到一种广义表旳图形体现。例如,上面五个广义表 旳图形体现如下图所示。
A() B(e) C(a,(b,c,d)) D(A(),B(e),C(a,(b,c,d))) E((a,(a,b),((a,b),c)))
AB e
C A
a b cd
D BC
ea b cd
E
a
ab
c
ab
8.2 广义表旳存储构造
广义表是一种递归旳数据构造,所以极 难为每个广义表分配固定大小旳存储空间,所
GLNode *CreatGL(char *&s)
{ GLNode *h;char ch=*s++; /*取一种扫描字符*/
if (ch!='\0')
/*串未结束判断*/
{ h=(GLNode *)malloc(sizeof(GLNode));/*创建新结点*/
数据结构之数组与广义表课件PPT课件
对称矩阵有n*n个元素,但只存储n*(n+1)/2 个元素即可. 若以行序为主序,把下三角中的 元素,存储在一个一维数组SA[n*(n+1)/2] 中, 则 A[i,j] 和SA[k] 的对应关系如下:
若 i>=j , 则A[i, j]在下三角中,A[i, j]之前共有 1+2+……+i+j = i*(i+1)/2+j 个元素,因此有
2
3 -1
3
1
-1
6
4
5
2
8
6
1
5
7
6
9
7 7 7
t: 1 3 -1
165 212 258 3 1 -1 634 679
➢ 基本思想:
把S转置成T,就是把S中的每一个三元组的 行号和列号(row 和col)交换,并存储在T 中。但是,这样的结果是按列优先存储的稀 疏矩阵T,所以,还必须重新排列三元组的 顺序。
3.稀疏矩阵的压缩存储
➢ 若一个m*n矩阵,有s个非0元素, 记 e=s/(m*n) e 称为稀疏因子。 当 e0.05时,则称为稀疏矩阵。
例: M=
0 2 -1 0 0 0 0 0000000 -1 0 0 0 0 4 0 0000000 0800000 5000000 0000090
➢ 在稀疏矩阵中,非0元素的排列无规律,所以不 能采用以前的压缩方法。
1. 一维数组的寻址公式
对于一维数组,若其第一个元素的首地
址为Loc(a0),下标为 i 的数组元素A[i]的地
址为Loc(ai),
a a 则 Loc( i) = Loc( 0) + k * i
( 0≤i≤n-1)
数据结构 第三章(广义表)
线性表L
= <a1, …, ai,…,an>
使用单链表存储 结点包含有数据域data和指针域next 指针p指向值为ai的节点。
先建立存放x0的结点
递归建立与‚x1, …, xn-1)”对应的表尾,并链接 到存放x0的结点之后
如果x0是子表 则x0一定以左括号开头 x0的其它部分一定为‚y0, …, ym-1)”形式 可以递归建立与之对应的子表
若x0不以左括号‚(”开头 则x0是原子
直接存入相应结点即可
左括号是重要的导航标记。在顶层,第一个符号一定 是左括号。
写为A = (a0, a1, …, an-1)
A是名字,n是表的长度。按惯例,表名 用大写字母表示,原子用小写字母表示。如果 n≥1,则a0是A的表头,(a1, …, an-1)是A的表尾
广义表的例子:
(1)D = ( ):长度为0的空表。 (2)A = (a, (b, c)):长度为2的表,其第一个元素是 原子a,第二个元素是表 (b, c)。 (3)B = (A, A, ( )):长度为3的表,其前两个元素是 表A,第三个元素是空表。 (4)C = (a, C):长度为2的递归表,C = (a, (a, (a, …),具有无限层次。
A
B
C
E
A
A b c B a
b
c
a
.
b
c
a
(d) E=(a,E)
(a)A=(b,c)
数据结构Ch5数组和广义表-PPT文档资料
不失一般性,存储下三角(包括主对角线),以行
主序存储:
a00 a10 a11 a20 a21 a22 ... an-10 an-11 ...an-1n-1
10
( i 1 )nn ( 1 )/2 元素个数
i 0
n 1
§5.2 矩阵的压缩存储
压缩存储: 将其存于向量sa[0..n(n+1)/2-1]中。 如何访问aij?必须将其与sa[k]的对应关系找出来。
sa[0..n(n+1)/2]
将C存于最后一个分量中。
12
§5.2 矩阵的压缩存储
3. 对角矩阵
总结:这类矩阵压缩存储后能找到地址计算公式, 使其保持随机存取的功能。
13
§5.2 矩阵的压缩存储
§ 5.2.2 稀疏矩阵
mn ,称A为 定义:设Amn中有t个非零元素,若t 稀疏矩阵。 t 0.05 一般非零元素分布无规律性 稀疏因子: mn 压缩存储:
§5.2.1 特取功能。
重 复 元 素 分 布 有 规 律 元 素 零
9
§5.2 矩阵的压缩存储
1. 对称阵
a i ,j n1 ,则称A为对称阵。 n阶方阵A,若 a i j j i0
因为矩阵元素关于主对角线对称,故只存上三角或 下三角元素即可,节约近一半空间。
只存储非零元,故须存储辅助信息,才能确 定其位置。
三元组 (i , j , aij) :(行号,列号,非零元的 值)唯一确定一个非零元。 当用三元组表示非零元时,有两种压缩方式: 顺序和链式。
14
§5.2 矩阵的压缩存储
1. 三元组顺序表(三元组表)
以行主序(或列主序)的顺序存储非零元,跳 过零元。得到一个其节点均是三元组的线性表, 称此顺序存储结构为三元组表。