C语言 一元稀疏多项式的运算

C语言 一元稀疏多项式的运算,第1张

#include #include #include #include using namespace std; typedef struct Polynode { float coef; //系数 int exp; //指数 }Poly,Polynode; //Poly为指针类型 int n,m;//全局变量 void Sort(Poly &p,int l)//按指数的升序排序 { int i,j,small; Polynode temp; for(i=0;ia[i]exp; } cout>b[i]exp; } Sort(a,n); Sort(b,m); } void OutputList(Poly a,int l)//输出多项式 { int flag=1,i,k=0;//项数计数器 if(l==0) //若多项式为空,输出0 { printf("0\n"); } for(i=0;i0&&flag!=1) //系数大于0且不是第一项 printf("+"); if(a[i]coef!=1&&a[i]coef!=-1)//系数非1或-1的普通情况,-+1要特别处理 { cout

#include <iostream>

#include <string>

using namespace std;

void main()

{

int student_age[3][2] = {19 ,20 ,19 ,21 ,22 ,20};//2维数组就相当于一个简单的矩阵 ,用此矩阵来存储 学生的年龄 int length_col = sizeof(student_age[0])/4;//每一列的个数

int length_row = sizeof(student_age)/sizeof(student_age[0]);////每一行的个数

for(int i = 0;i <length_row ; i++)

{

cout << "数组中第" << i<< "行" << "学生的年龄为:" << endl;

for(int j = 0 ; j <length_col ; j++)

{

cout << student_age[i][j] << endl;

}

}}

线性代数是大学理工科学生的必修课。学过线性代数的同学一定对矩阵不陌生,因为线性代数就是一门关于矩阵的学科。

程序设计中有一种储存数据的方式是二维数组,而二维数组本质上就是矩阵。但是,假如我们想要用二维数组去储存一个大规模的矩阵并进行运算的话,会造成很大的资源浪费。举个例子,假如我们想要用二维数组去储存一个20W20W的单位矩阵,事实上其中只有20W个数是1,其他数字都是0。所以,我们或许可以利用一种“忽略矩阵中的0项”的方式,来实现对矩阵的压缩储存,这种储存方式就叫做稀疏矩阵。对于大部分位置都是0,只有少部分位置有值的矩阵来说,使用稀疏矩阵可以让矩阵的储存密度大大提高。

我们可以使用一个 二维单向链表 来储存稀疏矩阵——因为链表在插入方面具有极低的时间复杂度,可以保证一个稀疏矩阵在经过各种运算后依然保持行与列间有序的组织。为了能够实现单向链表的删除,我们需要指向每一个有值结点前一个结点的引用。为此,我们还需要在第一行设置一个空行结点,每一行的第一列设置一个空列结点。形象地说,这种组织方式如下图所示:

使用链表的代价是寻址成本的提高,因此二维迭代器的封装对于基于链表的稀疏矩阵也是必不可少的。此外,比起二维数组矩阵,在各项 *** 作方面,稀疏矩阵更难做到高效。因此如何高效地进行稀疏矩阵的各项 *** 作也是本文需要探讨的话题。

本文中需要实现的稀疏矩阵基本 *** 作如下:

同时稀疏矩阵还有派生类稀疏方阵,它实现的基本 *** 作如下:

基于链表的稀疏矩阵的基础是行索引。因为我们定位一个矩阵中的元素,是先定位其行位置,再定位其列位置的。

因此矩阵包含了 一个作为基准的行索引链表结点 。这个结点包含一个值,代表行号;包含一个横向指针指向一个列索引链表结点(在C#中就是对一个列索引链表结点的引用),也就是该行第一个有非0元素的列;包含一个纵向指针指向下一个有非0元素的行索引链表结点。

矩阵的基础构造与行索引链表结点如下所示:

当确定矩阵中元素所在的行时,再通过列索引链表确定元素所在的列,就可以将该元素定位了。因此,列索引链表中包含两个值,一个表示自己的列号,一个表示由行索引和列索引确定的元素的值。此外,还包含一个指向和自己同行的下一个非0元素的引用。

由于二维链表在定位元素时需要先在行索引链表中寻址,再在列索引链表中寻址,其时间复杂度为 $o(n)$ ,因此在实现诸如矩阵遍历等有序 *** 作时必须依赖二维迭代器,否则会造将大量时间浪费在寻址上,其时间复杂度将是无法想象的。 为矩阵维护一个包含一个行索引结点引用、一个列索引结点引用的对象,它将通过四个引用,分别指向一行、一列和该行的前一行、该行的前一列 ,并且通过所引用的结点内部包含的、指向其他结点的引用来实现自身所指元素的移动。

迭代器在初始化或者行复位时需要 将指向前一行的引用放置到矩阵结构的“第0行”上,将指向当前行的引用放置到第一行 。同理,每移动到下一行或者进行列复位,都要 把指向前一列的引用放置到该行的“第0列”上,将指向当前列的引用放置到第一列

迭代器实现了五个方法,分别是 移动到下一列、移动到下一行并指向该行第一列、移动到该行第一列、在当前指向行和前一行之间插入行、在当前指向列和前一列之间增加列 。此外,在大类中还实现了一个私有方法reLine,用来 将迭代器恢复至整个稀疏矩阵第一 行。在大类中 声明一个迭代器对象 ,用来方便省时地访问其中的元素。

利用迭代器指向矩阵中的元素,可以单独设置这个元素的内容。而如果要求设置一个不超出矩阵大小,但原本不存在(也就是为0)的位置的元素,就需要在二维链表中插入行或列。这一判断需要依靠迭代器来作出。比如,若迭代器判定其指向位置的前一行小于目标行、而当前行大于目标行,就要在当前位置前插入目标行。同理,如果把一个原本不为0的位置的元素设为0,就要删除当前列,而列为空时,则要删除当前行。

而单个元素的加减和乘除本质也是相同的。记住要分成三种情况考虑需要实现的 *** 作:

而获取单个元素使用的方法也运用同样的思想,只不过在获取不到元素时返回元素类型的默认值。

默认初始化时,用户需要指定该矩阵的行数和列数。此外,将迭代器置于第一行第一列,虽然此时第一行第一列没有声明,但是要记得我们矩阵的链表结构中存在一个空的“第0行”。将迭代器的preline引用指向该“第0行”,其他引用则设为null。

使用其他mat初始化时,稀疏矩阵会调用目标矩阵中的迭代器和自身的迭代器来实现矩阵遍历。遍历只需要 不断调用nextRow方法,在指向的列为空时调用nextLine方法,直到指向的行为空为止即可

在这里强调一下reLine的作用,它是 迭代器的复位方法 ,也可以视为声明一个指向第一行第一列的迭代器。如果不进行reLine的话,假如目标矩阵中的迭代器已经指向了一个很后面的元素,那么利用迭代器nextRow和nextLine方法进行的遍历就是不成立的。

使用二维数组初始化通过遍历二维数组的方式,将二维数组中的数据一个一个set到矩阵当中。

矩阵的加减用第一个矩阵初始化一个新矩阵,同时用新矩阵和第二个矩阵的迭代器遍历两个矩阵,再在新矩阵的每个位置调用加方法,加上第二个矩阵对应位置的元素值(或其相反数),最后把新矩阵返回。

矩阵的数乘用第一个矩阵初始化一个新矩阵,同时用新矩阵的迭代器遍历新矩阵,再在新矩阵的每个位置调用乘方法,乘上目标值,最后把新矩阵返回。

依然通过迭代器来选取两个矩阵里的元素,通过矩阵乘法的特殊运算顺序来运算,将结果放进新矩阵中。返回的矩阵是通过new创建的新矩阵,因此不会对原来两个矩阵产生影响。

矩阵转置创建一个新的矩阵,其行数为原矩阵的列数,列数为原矩阵的行数,并将原矩阵中的元素所在行列对换后放进新矩阵中。

基本上就是从矩阵当中继承了初始化方法。注意构造函数是要继承自base(父类构造函数参数)的。以及行和列的数目应该相同。

都是对稀疏矩阵基本运算的重写。由于行列数目相同,实际实现会容易得多。

求行最简矩阵的目的就是把原矩阵通过初等行变换化为相抵的上三角矩阵。其具体做法是:

求完行最简矩阵之后,求行列式的值也变成了非常简单的工作。只需把对角线上所有元素相乘即可。

逆矩阵同样通过初等行变换法来解出,方法是把一个行列数与原矩阵相同的单位矩阵进行和原矩阵同步的行变换。当把原矩阵变成单位矩阵时,单位矩阵也变成了原矩阵的逆矩阵。

矩阵加减注意格式

#include <stdioh>

#define maxsize 20

typedef int data;

typedef struct

{

int i,j;

data v;

}mat;

typedef struct

{

int m,n,t;

mat dtt[maxsize+1];

}matrix;

matrix a,b,c;

void transmat(matrix a,matrix b)

{

int p,q,col;

b->m=an;

b->n=am;

b->t=at;

if(at!=0)

{

q=1;

for(col=1;col<=an;col++)

for(p=1;p<=at;p++)

if(adtt[p]j==col)

{

b->dtt[q]j=adtt[p]i;

b->dtt[q]i=adtt[p]j;

b->dtt[q]v=adtt[p]v;

q++;

}

}

}

void creat(matrix x)

{

printf("\nn,m,t=");

scanf("%d,%d,%d",&x->n,&x->m,&x->t);

for(int i=1;i<=x->t;i++)

{

printf("\ni,j,v=");

scanf("%d,%d,%d",&x->dtt[i]i,&x->dtt[i]j,&x->dtt[i]v);

}

}

void mout(matrix x)

{

printf("\nn,m,t=");

printf("%d,%d,%d\n",xn,xm,xt);

for(int i=1;i<=xt;i++)

{

printf("\ni,j,v=");

printf("%d,%d,%d\n",xdtt[i]i,xdtt[i]j,xdtt[i]v);

}

}

void jiajian(matrix x,matrix y,matrix b)

{

int t;

printf("\n1加");

printf("\n2减\n\n");

scanf("%d",&t);

if(t==1)

{

int s=0,j=1,z=1;

b->m=xm;

b->n=xn;

for(int i=1;i<=b->n;i++)

{

for(;j<=xt,z<=yt;)

{

if(xdtt[j]i!=i&&ydtt[z]i!=i)

{

break;

}

else if(xdtt[j]i!=i)

{

s++;

b->dtt[s]i=i;

b->dtt[s]j=ydtt[z]j;

b->dtt[s]v=ydtt[z]v;

z++;

}

else if(ydtt[z]i!=i)

{

s++;

b->dtt[s]i=i;

b->dtt[s]j=xdtt[j]j;

b->dtt[s]v=xdtt[j]v;

j++;

}

else if(xdtt[j]j>ydtt[z]j)

{

s++;

b->dtt[s]i=i;

b->dtt[s]j=ydtt[z]j;

b->dtt[s]v=ydtt[z]v;

z++;

}

else if(xdtt[j]j==ydtt[z]j)

{

s++;

b->dtt[s]i=i;

b->dtt[s]j=ydtt[z]j;

b->dtt[s]v=ydtt[z]v+xdtt[j]v;

z++;

j++;

}

else if(xdtt[j]j<ydtt[z]j)

{

s++;

b->dtt[s]i=i;

b->dtt[s]j=xdtt[j]j;

b->dtt[s]v=xdtt[j]v;

j++;

}

}

}

b->t=s;

}

else if(t==2)

{

int s=0,j=1,z=1;

b->m=xm;

b->n=xn;

for(int i=1;i<=b->n;i++)

{

for(;j<=xt,z<=yt;)

{

if(xdtt[j]i!=i&&ydtt[z]i!=i)

{

break;

}

else if(xdtt[j]i!=i)

{

s++;

b->dtt[s]i=i;

b->dtt[s]j=ydtt[z]j;

b->dtt[s]v=-ydtt[z]v;

z++;

}

else if(ydtt[z]i!=i)

{

s++;

b->dtt[s]i=i;

b->dtt[s]j=xdtt[j]j;

b->dtt[s]v=xdtt[j]v;

j++;

}

else if(xdtt[j]j>ydtt[z]j)

{

s++;

b->dtt[s]i=i;

b->dtt[s]j=ydtt[z]j;

b->dtt[s]v=-ydtt[z]v;

z++;

}

else if(xdtt[j]j==ydtt[z]j)

{

if(xdtt[j]v-ydtt[z]v!=0)

{

s++;

b->dtt[s]i=i;

b->dtt[s]j=ydtt[z]j;

b->dtt[s]v=xdtt[j]v-ydtt[z]v;

}

z++;

j++;

}

else if(xdtt[j]j<ydtt[z]j)

{

s++;

b->dtt[s]i=i;

b->dtt[s]j=xdtt[j]j;

b->dtt[s]v=xdtt[j]v;

j++;

}

}

}

b->t=s;

}

}

int main(int argc, char argv[])

{

printf("1创建\n");

printf("2转置\n");

printf("3矩阵加减\n");

printf("4退出\n");

printf("\n\n\n");

int t;

while(~scanf("%d",&t))

{

if(t==1)

{

creat(&a);

}

else if(t==2)

{

transmat(a,&b);

mout(b);

}

else if(t==3)

{

creat(&c);

jiajian(a,c,&b);

mout(b);

}

else if(t==4)

break;

printf("\n\n\n");

printf("1创建\n");

printf("2转置\n");

printf("3矩阵加减\n");

printf("4退出\n");

printf("\n\n\n");

}

return 0;

}

以上就是关于C语言 一元稀疏多项式的运算全部的内容,包括:C语言 一元稀疏多项式的运算、数组的应用,稀疏矩阵如何存储要写出C++程序代码…谢谢!、C#数据结构(4) 稀疏矩阵与稀疏方阵等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zz/9686947.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-30
下一篇 2023-04-30

发表评论

登录后才能评论

评论列表(0条)

保存