D4-数组

news/2024/11/16 22:37:38/

1.只有引用型操作,即只改变数组元素中的值,没有加工型操作,即不做插入删除操作

2.数组是多维结构,存储空间是一维结构

顺序映象方式:

1.行序为主序(低下标优先)

2.列序为主序(高下标优先)

eg:若三维数组[0,1][0,1,2][0,1],以行序为主序,排列为(0,0,0),(0,0,1),(0,1,0),(0,1,1)..

以列序为主序,排列为(0,0,0),(1,0,0),(0,1,0),(1,1,0),(0,2,0),(1,2,0)...

假设每个元素占用L个存储单元,二维数组任意元素存储位置:LOC[i,j]=LOC[0,0]+(b2*i+j)*L;LOC[0,0]称基址或基地址

推广到n维:LOC[j1,j2,j3...]=LOC[0,0,0...]+L*该元素前的所有元素数,因此,数组元素的存储位置是线性函数,只要每个维度的长度确定,存储位置就确定,此时计算每个元素存储位置的时间相等,存储每个元素的时间是一样的,称其为顺序存储。

对于一个m行n列的数组,若其中存有t个非零元素,设t/(m*n)为稀疏因子,一般设稀疏因子小于0.05的矩阵为稀疏矩阵。稀疏矩阵存储时有大量的零,浪费存储空间,此外对稀疏矩阵做运算时对每个元素都需要判断与零的运算,大幅增大运算时间,因此需要对稀疏矩阵进行讨论,尽可能减少与零元素的计算,尽可能少存零元素,此外还要尽快找到所需要的元素。

矩阵转置的经典算法时间复杂度O(mu*nu),下面的算法会减少时间的使用

1.三元组法

#define MAXSIZE 12500
typedef struct {int i, j;//行数和列数int e;//元素值
}Triple;
typedef struct {int mu, nu, tu;//三元组行数、列数、非零元素个数Triple data[MAXSIZE + 1];//data[0]储存长度
}TSMatrix;

在Triple的基础上定义第二个结构体TSMatrix有利于某些矩阵运算如计算转置矩阵等,求转置矩阵的时间复杂度为O(mu*nu),代码双重循环即可实现。

表示方式:((arr1,col1,num1),(arr2,col2,num2),(arr3,col3,num3)...)即可得到唯一的数组。

在双重循环求三元组的基础上可以加上两个辅助变量,首先按列求出相同列的元素数目记为Num为一个一维数组,再创建一个新数组cPot记录从第一列开始前n列非零元素之和。

下图为示例,左边为按行增序排列,右边为按列增序排列

 代码实现如下

int FastTransposeMatrix(TSMatrix T, TSMatrix* S) {S->mu = T.mu;S->nu = T.nu;S->tu = T.tu;int num[MAXSIZE], cpot[MAXSIZE], i ,col;for (i = 1; i <= T.nu; i++)num[i] = 0;for (i = 1; i <= T.tu; i++)num[T.data[i].j]++;cpot[1] = 1;for (i = 2; i <= T.nu; i++)cpot[i] = cpot[i - 1] + num[i + 1];//双重循环转置矩阵
}

若随机存取则从头查找,可以方便处理按顺序存储的矩阵

2.行逻辑连接的顺序表

给出结构定义

#define MAXMN 500
typedef struct {int mu, nu, tu;//三元组行数、列数、非零元素个数Triple data[MAXSIZE + 1];//data[0]储存元素个数int rpos[MAXMN + 1];
}RLSMatrix;

在快速算法中,虽然加快了速度,但是在M或N对应元素相乘时,若某一元素为零,结果显然为零,快速算法没有考虑到这种情况,因此用rpos存储有关信息进而加速。

实际操作时,使用累加器ctemp,假设M矩阵有i行j列,i从1到n,对每一行都先检测是否有N矩阵的列与其相乘结果不为零,即M(i,j)与N(j,k)相乘,并对于不同的k将接过放在不同的累加器中。对每一行都可以将乘出的Q(i,k)存储进Q.data中。Q.data视做一个一维数组,rpos记录每行第一个非零元素在Q.data中的位置。

代码实现如下

int MultSMatrix(RLSMatrix M, RLSMatrix N, RLSMatrix* Q) {int arow, brow, tp, p, q, tq, ccol;int ctmp[];//累加器if (M.nu != N.mu) {printf("ERROR");return 0;}Q->mu = M.mu, Q->nu = N.nu, Q->tu = 0;if (M.mu * N.nu != 0) {for (arow = 1; arow = M.mu + 1; arow++) {ctmp[arow] = 0;if (arow < M.mu)tp = M.rpos[arow + 1];elsetp = M.tu + 1;for (p = M.rpos[arow]; p < M.rpos[arow] + 1; p++) {if (brow < N.mu)tq = N.rpos[arow + 1];elsetq = N.tu + 1;for (q = N.rpos[arow] + 1; q < tq; q++) {ccol = N.data[q].j;ctmp[ccol] += M.data[p].i * N.data[q].j;}}}for (ccol = 1; ccol <= Q->nu; ccol++) {if (ctmp[ccol]){Q->data[Q->tu] = (arow, ccol, ctmp[ccol]);if (Q->tu++ > MAXSIZE) {printf("ERROR");return 0;}}}}return 1;
}

该方法的时间复杂度为O(M.mu*N.nu)。

3.十字链表

若矩阵中非零元个数变化较大时,宜使用十字链表。例如两个矩阵相加,此时可能非零元素变为零元素,或零元素变为非零元素,若使用上面两种算法,元素的位置变化会比较多且繁杂。

十字链表总体需要五个变量:非零元素,该元素所在的行列数和系数矩阵的行列数。每存储一个非零元素,有right和down指针指向同一行和同一列的下一个非零元素;为便于寻找数据,用一维数组mhead和rhead存储每一行、列的头指针。由此得出结构体定义

typedef struct _ONode {int i, j;//非零元素所在的行号列号int e;//非零元素的值struct _ONode* right, * down;//指向右和向下的指针
}ONode, * OLink;typedef struct {OLink* mhead, * rhead;int mu, nu, tu;//稀疏矩阵的行数、列数、非零元素个数
}CrossList;

*对pq定义类型存疑

建立十字链表

int CreateMatrixLink(CrossList* M) {if (M)free(M);int m, n, t;scanf("%d %d %d", &m, &n, &t);M->mu = m, M->nu = n, M->tu = t;//初始化结点if (!(M->mhead = (OLink*)malloc(sizeof(OLink) * (m + 1))))exit(OVERFLOW);if (!(M->chead = (OLink*)malloc(sizeof(OLink) * (n + 1))))exit(OVERFLOW);M->mhead = M->chead = NULL;int i, j, e;for (scanf(&i, &j, &e);i!=0; scanf(&i, &j, &e)) {if(!(p=(ONode*)malloc(sizeof(ONode))))exit(OVERFLOW);p.i = i, p.j = j, p.e = e;//p从行头插入,第i行无元素或M.head[i]结点在p右边的情况if (M->mhead[i] == NULL || M->mhead[i]->j > j) {p.right = M->mhead[i];M->mhead[i] = p;}//M.head[i]在p左边(一般情况)else {//对第i列进行行插入for (q = M.mhead[i]; (q.right.j < j) && (q.right); 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.i < i) && (q.down); q = q.down) {p.down = q.down;q.down = p;}}}return 1;
}

 对稀疏矩阵相加有四种情况:

1.a矩阵元素为零,则结点值为b矩阵元素值

2.b矩阵元素为零,则结点值不变

3.元素值变为ab矩阵元素值相加

4.值变为0,删除该结点地址

实现时,设指针pa,pb指向某行,pa==NULL表示该行没有非零元

pa->j < pb->j
//向右移动pa即可,递推(pa->j == pb->j) && (pa->e + pb->e == 0)
//删除pa指向的结点地址,同时要注意改变pa前一个的right值和上一个的down值(指向另外的结点地址)(pa->j == pb->j) && (pa->e + pb->e != 0)
//改变pa指向的结点值即可pa->j > pb->j || pa == NULL;
//在pa前增加一个结点地址,改变同一行中前一个结点的right和同一列中上一个节点的down

代码实现较容易,不过多叙述

广义表

广义表一般记为LS=(a1,a2...an),广义表中的数据如果是单个元素称为原子,如果是广义表则称为子表。原子的深度为0,子表的深度为1。n为广义表的长度,深度为广义表括号的重数,原子的深度为0,空表的深度为1。

广义表如果非空,称第一个数据为表头,其余的数据为表尾。若表中无元素,长度为0,为空表,表示为LS=();若只有一个子表且为一个空表,则表头和表尾均为空,长度为1,表示为LS=(())。广义表的子表也可以是它本身,因此他是一个递归结构,可以看做递归版的链表。

由于表中元素有不同的类型,因此定义广义表的结构体时要用到枚举和联合,同时需要一个标记域。对表结点,存在标记域和前后两个指针,对原子结点,存在标记域和向后指的指针。

定义结构体有两种不同的方法

//递归构建广义表
typedef enum { ATOM, LIST }tag;
typedef struct GLNode{int tag;union {AtomType atom;struct { struct GLNode* hp, * tp; }ptr;};
}*GList;//由于表结点和原子结点都需要向后指的指针,所以可以将原子结点的元素与表结点的前指针联合声明
typedef enum { ATOM, LIST }tag;
typedef struct GLNode {int tag;union {AtomType atom;struct GLNode* hp;};struct GLNode* tp;
}*GList;

广义表主要的操作为递归实现求广义表的深度,新建一个广义表,复制一个广义表。

//求广义表的深度
int DepthGLists(GList& GL) {if (!GL)max = 1;if (GL->tag == ATOM)max = 0;for(max=0,p=GL;p;p=GL->ptr.tp){if (DepthGLists(p.ptr.hp) > max)max = DepthGLists(p.ptr.hp);return max;
}
//复制广义表
//第一种定义方式int CopyGLists(GList & GL, GList L) {if (!GL)return ERROR;else {if(!(L = (GList)malloc(sizeof(GNode))))exit(OVERFLOW);L.tag = GL.tag;//在第一种定义方式下,原子结点只有一个域if (GL.tag == ATOM)L.atom = GL.atom;else {CopyGLists(GL.ptr.hp, L.ptr, hp);CopyGLists(GL.ptr.tp, L.ptr, tp);}}return OK;
}
//由一个字符串建立广义表int CreateGLists(GList& GL,SString S) {if (!GL)return NULL;else {if (!(p = (GList)malloc(sizeof(GLNode)));exit(OVERFLOW);else {sever(sub, hsub);//对表头建立广义表if (Strlength(hsub) == 1) {p.ptr.hp->tag = ATOM;p.ptr.hp->atom = hsub;}else {CreateGLists(p.ptr.hp, hsub);}//对表尾建广义表if (!StrEmpty(sub)) {CreateGLists(p.ptr.tp, sub);}elsep.ptr.tp = NULL;}}
}


http://www.ppmy.cn/news/287325.html

相关文章

【rmzt:新网球王子动漫主题】

新网球王子动漫主题热门主题之家 系统&#xff1a;图标下载&#xff0c;Windows 7 大小&#xff1a;2.83 MB 主题简介 新网球王子是根据许斐刚的知名体育漫画改编的&#xff0c;网球王子们不但美型&#xff0c;而且他们更开创了打网球险些能够杀人的先河。而随著小不点越前龙马…

百度中文搜索风云榜每天对上亿次搜索进行分析,权威、全面、准确、精彩!...

百度中文搜索风云榜每天对上亿次搜索进行分析&#xff0c;权威、全面、准确、精彩&#xff01;凸现热点&#xff0c;纵览风云&#xff0c;挖掘萦绕在我们身边的新奇和惊喜&#xff0c;透过搜索&#xff0c;把握世界 2007风云榜行业报告&#xff0c;洞察行业趋势 上升最快Top50…

【分享rmzt:网球王子立海大动漫主题】

网球王子立海大动漫主题 系统&#xff1a;Win7主题下载&#xff0c;windows7 大小&#xff1a;3.28 MB 主题简介&#xff1a; 新网球王子是根据许斐刚的知名体育漫画改编的&#xff0c;网球王子们不但美型&#xff0c;而且他们更开创了打网球险些能够杀人的先河。而随著小不点…

刘润年度演讲2021:进化的力量(演讲全文)

‍‍ 周六通过直播看了刘润老师的演讲&#xff0c;不得不说&#xff0c;刘润老师是真的牛逼&#xff0c;五个小时的演讲&#xff0c;没喝过一口水&#xff0c;没去过一次厕所&#xff0c;就这份耐力就非常人。没人不辛苦&#xff0c;只是有人不说疼&#xff01; 以下是刘润老师…

win10 下 acdsee7 在普通账户下无法运行并崩溃的 BUG

win10 下 acdsee7 在普通账户下无法运行并崩溃的 BUG&#xff0c;而在管理员账户下却可以正常运行勉强可以使用的问题... 作为一款图片管理程序&#xff0c;虽然有一些 BUG&#xff0c;但却比它之后的版本要运行的快速而体积小巧的多。在全屏看图时&#xff0c;不会被之后版本中…

用acdess制作html文件,使用ACDSee制作图片注释

用过ACDSee的人无不被它强大而实用的看图功能所折服&#xff0c;其方便的描述信息功能就是其中之一。你可以为任何格式的图片加上自己的文字注释&#xff0c;方便检索和增添许多情趣。只要将鼠标指向一个图像文件&#xff0c;就可以显示出图像的文件名、大小、规格和描述信息&a…

html相册 自动,ACDSee的HTML相册生成

照片汇总和批量重命名 可以先将所有的数码相机的照片汇总到一个目录下后&#xff0c;按照时间排序并批量重命名 按时间排序&#xff1a;在ACDSEE的浏览器模式下按&#xff1a;F12 按照详细资料列表模式浏览&#xff0c;如果列表字段中没有最后更新时间(modified)字段&#xff0…