稀疏矩阵相乘.docx

上传人:b****3 文档编号:4664826 上传时间:2022-12-07 格式:DOCX 页数:19 大小:95.98KB
下载 相关 举报
稀疏矩阵相乘.docx_第1页
第1页 / 共19页
稀疏矩阵相乘.docx_第2页
第2页 / 共19页
稀疏矩阵相乘.docx_第3页
第3页 / 共19页
稀疏矩阵相乘.docx_第4页
第4页 / 共19页
稀疏矩阵相乘.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

稀疏矩阵相乘.docx

《稀疏矩阵相乘.docx》由会员分享,可在线阅读,更多相关《稀疏矩阵相乘.docx(19页珍藏版)》请在冰豆网上搜索。

稀疏矩阵相乘.docx

稀疏矩阵相乘

稀疏矩阵相乘

1问题描述

1.1稀疏矩阵的三元组及十字链表表示

(1)稀疏矩阵及其三元组表示

行(row)

列(col)

值(value)

[0]

0

3

22

[1]

0

6

15

[2]

1

1

11

[3]

1

5

17

[4]

2

3

-6

[5]

3

5

39

[6]

4

0

39

[7]

5

2

28

稀疏矩阵

 

(2)稀疏矩阵的十字链表表示

1.2基本要求

(1)以“带行逻辑链接信息”的三元组表示稀疏矩阵;

(2)输入矩阵用三元组顺序输入;

(2)稀疏矩阵采用十字链表表示;

(3)实现两个矩阵相乘的运算,而运算结果的矩阵则以通常的阵列形式列出。

2设计思路

2.1存储结构设计

2.1.1三元组表示稀疏矩阵

只存储矩阵中极少的非零元素,采用来唯一地确定每一个非零元素,其中row、col、value分别表示非零元素在矩阵中的的行下标、列下表和值。

各数组元素的三元组按在原矩阵中的位置以行优先的顺序依次存放。

structtriple

{//三元组结构定义

introw,col;//非零元素行号,列号

Floatvalue;//非零元素的值

triple&operator=(triple&x)

{row=x.row;col=x.col;value=x.value;}

};

2.1.2十字链表表示稀疏矩阵

structelement{introw,col;floatvalue;};

classMatrix;

classnode

{//矩阵节点类的定义

friendclassMatrix;

public:

node():

head(true){right=down=this;}//建立附加头结点

node(element*t)//建立非零元素结点

{

triple.col=t->col;

triple.row=t->row;

triple.value=t->value;

right=down=this;

head=false;

}

node*down,*right;//行列链表指针

boolhead;

union{elementtriple;node*next;};//无名联合

};

classMatrix

{//稀疏矩阵的类定义

friendistream&operator>>(istream&,Matrix&);

friendostream&operator<<(ostream&,Matrix&);

private:

intRow,Col,Terms,temp;//矩阵的总行数,总列数,和非零元素个数和临时变量;

node*headnode;//稀疏矩阵的总表头

public:

Matrix(intm,intn);//重载构造函数

Matrix();//对矩阵进行构造

Matrix(Matrix&T);//复制构造函数

~Matrix(){makeEmpty();}//析构函数

voidInit(intm,intn);//初始化函数,又来初始化无参构造函数构造的矩阵

voidmakeEmpty();//清空矩阵

voidInsert(intm,intn,floatp);//插入矩阵元素

node*Locate(inti);//定位附加头结点

MatrixMul(Matrixb);//两个矩阵相乘

Matrix&operator=(Matrix&T);//重载赋值号

};

在稀疏矩阵的十字链表表示中,矩阵的的每一行设置为一个带附加头结点的循环行链表,每一列也设置为一个带附加头结点的循环列链表。

链表中的结点都属于类node的对象,这个类包含一个域head,它用于区分改结点是附加头结点还是链表中的非零元素结点;head=true,表示该结点是附加头结点;head=false,表示该结点是矩阵中的非零元素结点。

每一个附加头结点还有三个域:

down、right、next。

第i个行链表和第i个列链表共用一个附加头结点,在它的right域存放第i行链表最前端的第一个结点的地址,在它的down域存放第i列链表的最前端第一个结点的地址,通过next域链接到第i+1个附加头结点。

每一个非零元素结点包含六个域:

head,row,col,down,right,value。

Down存放列链表指针,right存放行链表指针。

整个稀疏矩阵定义为类Matrix的一个对象,*headnode给出整个附加头结点链表的附加头结点的地址。

head

next

down

right

head

row

col

down

value

right

非零元素结点

附加头结点非零元素结点

2.2主要算法

基于三元组及十字链表的稀疏矩阵乘法

MatrixMatrix:

:

Mul(Matrixb)//矩阵乘法的实现

{

if(this->Col==b.Row)

{

MatrixC(this->Row,b.Col);//以A矩阵的行和b矩阵的列为行列建立稀疏矩阵

floatvalue;

node*Row_head,*Col_head;//设两个指针,一个充当行头指针,一个为列指针for(inti=1;i<=temp;i++)//先确定行,再求出C矩阵在该行各列的元素

{

for(intj=1;j<=temp;j++)//通过确定列头指针来实现遍历相乘

{value=0;

Row_head=Locate(i);

Col_head=b.Locate(j);

while(Row_head->right!

=Locate(i))

{//假如行中还有元素不为零就找与之匹配的元素相Row_head=Row_head->right;

Col_head=Col_head->down;

while(Row_head->triple.col!

=Col_head->triple.row

&&Col_head->down!

=b.Locate(j))

{//假如行列不相等而且对应列还有元素,就继续找匹配的元素否则判断再环

if(Row_head->triple.col>Col_head->triple.row)

Col_head=Col_head->down;

else{

if(Row_head->right==Locate(i))

Col_head=Col_head->down;//假如b矩阵该列元素比a矩阵该行元素elseRow_head=Row_head->right;

//则b中该列元素已经无法找到能相乘元素则往下推直至跳出循环

}

}

if(Col_head->down!

=b.Locate(j)||Col_head->triple.row==Row_head->triple.col)

{value+=Row_head->triple.value*Col_head->triple.value;}

}

if(value!

=0){C.Insert(i,j,value)}

}

}

returnC;

}

else{MatrixC;

cerr<<"输入的两个矩阵不符规则,不能相乘!

"<

returnC;

}

}

2.3测试用例

3调试分析

3.1调试过程

(1)编译时程序中没有语法错误,但是格式及语句的书写错误叫多,按照编译错误提示一次改正错误,直至编译正确。

(2)运行程序。

以三元组的形式,即输入矩阵的行数、列数、非零元素个数和各非零元素的行、列、值,输入两个稀疏矩阵,输出了两个矩阵及它们的乘积。

(3)问题:

输出的矩阵不符合要求,形成的阵列中只有非零元素,零元素都没有输出。

说明友元输入函数有问题,将元函数改为下面的函数后能正确输出矩阵阵列。

ostream&operator<<(ostream&out,Matrix&b)//输出函数

{node*x;

for(inti=1;i<=b.temp;i++)//先确定各行头结点的位置再遍历各行,以输出所有非零元

{

x=b.Locate(i);

x=x->right;

for(intj=1;j<=b.temp;j++)

{if(x->head==false&&(x->triple.col==j)

{

cout.width(4);

out<triple.value;

x=x->right;

}

elseif(x->head==true)

{for(j;j<=b.temp;j++){cout.width(4);cout<<"0";}break;}

else{cout.width(4);cout<<"0";}

}

cout<

}

returnout;

}

3.2设计分析

(1)此程序中乘法算法的时间复杂度为O(Rows*Cols)。

(2)此程序没有将类做成模版,导致只能输入floate型的值。

改进方案:

将所有的类做成模版,将其属下的floate类型的全改为模版类型参数

(3)此程序显的很繁锁,算法比较复杂

(4)此程序只有稀疏矩阵的乘法,可以加入其他的矩阵运算来完善运算,也可以再主程序中设计选择菜单,实现多种运算。

(5)改进算法:

重新考虑算法,看是否可用数组加指针的方式实现,用数组可以简化找头指针的繁琐过程,简化循环的过程提高程序运行效率!

4经验与体会

我的题目是实现三元组,十字链表下乘法,运算。

看到这个题目的时候,我一片茫然,因为我们数据结构这一部分并没有讲,我根本就不知道十字链表是什么。

于是我赶紧看书,可是书上对十字链表的将就知识一笔带过,更不要指望在书上找到相关代码了。

于是我先学习了三元组数组的乘法算法,在这个基础上,我在网上收集各种资料收集和算法。

然后不断调试,不断改进程序,最终正确结果终于运行出来了。

我觉得自己的数据结构学得不好,但是数据结构可以说是计算机里一门基础课程,对于以后的学习尤为重要。

所以我们一定要把基础学扎实,这次的课内实践帮我重新巩固基础知识,也学了很多新知识,提高了我的专业的动手实践能力,也提高了我的对数据结构的学习兴趣。

此次课程设计过程中,我真正的体验到,拿到一个问题,应该先分析,将其的属性,功能分析清楚后,再进行细化,考虑其实现的具体的、有效的算法,有了整体的结构框架后再上机!

以前只要拿到题就直接打开电脑,想到什么就写什么,没整体思考,对小程序可以,大程序就会彻底崩溃。

编程实质就是问题的分析及其实现的算法,这两方面解决了上机编程才会得心应手,剩下的就是按算法些代码了!

确定一个好算法很难,一个人往往陷入死循环,思路受局限,找人讨论很必要,编程时团队意识很重要,这不是一个人就能搞定的。

在实践的过程中我每天完成一小部分。

尽量减少操作的盲目性,提高我们学习的效率。

有个总体的大纲来逐步实现。

我也曾经犯过这种错误。

每个函数都做出来部分,结果都没做完。

所以我们要养成有良好的时间规划的习惯,只有一步一步的进行,我们才能完成得更好。

同时在实验中我们要培养自己独立的思考能力和解决问题的能力,不能太过依赖于同学和网络,我们应该要有自己的想法,培养自己的编程思维。

实践能力对我们今后的发展也是至关重要的,我们只有拥有很好地实践能力,才有机会再编程这个领域有所发展。

子啊编程的过程中,我们应该积极的朝着更好地一面发展不断的完善程序,不能马马虎虎随便应付一下。

就像古人云,纸上得来终觉浅,得知此事要躬行。

为了以后的计算机道路,我们应该不断的提高自身的专业素养。

5附录

5.1程序

#include

#include

structelement{introw,col;floatvalue;};

classMatrix;

classnode

{//矩阵节点类的定义

friendclassMatrix;

public:

node():

head(true){right=down=this;}//建立附加头结点

node(element*t)//建立非零元素结点

{

triple.col=t->col;

triple.row=t->row;

triple.value=t->value;

right=down=this;

head=false;

}

node*down,*right;//行列链表指针

boolhead;

union{elementtriple;node*next;};//无名联合

};

classMatrix

{//稀疏矩阵的类定义

friendistream&operator>>(istream&,Matrix&);

friendostream&operator<<(ostream&,Matrix&);

private:

intRow,Col,Terms,temp;//矩阵的总行数,总列数,和非零元素个数和临时变量;

node*headnode;//稀疏矩阵的总表头

public:

Matrix(intm,intn);//重载构造函数

Matrix();//对矩阵进行构造

Matrix(Matrix&T);//拷贝构造函数

~Matrix(){makeEmpty();}//析构函数

voidInit(intm,intn);//初始化函数,又来初始化无参构造函数构造的矩阵

voidmakeEmpty();//清空矩阵

voidInsert(intm,intn,floatp);//插入矩阵元素

node*Locate(inti);//定位附加头结点

MatrixMul(Matrixb);//两个矩阵相乘

Matrix&operator=(Matrix&T);//重载赋值号

};

Matrix:

:

Matrix(intm,intn):

Row(m),Col(n)//重载构造函数的实现

{

elementx;

x.row=m;

x.col=n;

x.value=0;

Terms=0;

temp=m>=n?

m:

n;

node*current;

headnode=newnode(&x);

current=headnode->right=newnode();

for(inti=1;i

{

current->next=newnode();

current=current->next;

}

}

Matrix:

:

Matrix():

Row(0),Col(0),Terms(0)

{//构造函数的实现

elementx;

x.row=Row;

x.col=Col;

x.value=0;

}

Matrix:

:

Matrix(Matrix&T)//复制构造函数的实现

{

Init(T.Row,T.Col);

node*current;

for(inti=1;i<=temp;i++)

{

current=T.Locate(i);//定位行

while(current->right!

=T.Locate(i))

{//通过行遍历逐个赋值

current=current->right;

Insert(current->triple.row,current->triple.col,current->triple.value);

}

}

}

voidMatrix:

:

Init(intm,intn)//矩阵初始化函数的实现

{

Row=m;Col=n;Terms=0;

elementx;

x.row=m;x.col=n;x.value=0;

headnode=newnode(&x);

node*current;

if(m>0&&n>0)

{

temp=m>=n?

m:

n;

current=newnode();

headnode->right=current;

for(inti=1;i

{

current->next=newnode();

current=current->next;

}

}

else{cout<<"矩阵初始化错误!

"<

}

node*Matrix:

:

Locate(inti)//定位附加头结点实现

{

node*current;

current=headnode->right;

for(intk=1;k

{

current=current->next;

}

returncurrent;

}

voidMatrix:

:

Insert(intm,intn,floatp)//插入函数的实现

{

elementx;

x.row=m;x.col=n;x.value=p;

if(m<=this->Row&&n<=this->Col)

{

node*Newnode=newnode(&x),*current,*head;

head=Locate(m);//先定位行的位置再寻找列插入

current=head->right;

if(current==head)

{

current->right=Newnode;

Newnode->right=current;

}

else

{

while(current->triple.colright!

=head)

{

current=current->right;

}

Newnode->right=current->right;

current->right=Newnode;

}//完成插入

head=Locate(n);//先定位列再寻找行插入

current=head->down;

if(current==head)

{

current->down=Newnode;

Newnode->down=current;

}

else

{

while(current->triple.rowdown!

=head)

{

current=current->down;

}

Newnode->down=current->down;

current->down=Newnode;

}

Terms++;

}//完成插入

else

{

cout<<"输入的结点位置超出了范围,请重新输入!

"<

}

}

istream&operator>>(istream&in,Matrix&b)//输入函数重载的实现

{

intM,N,m,n,T;floatp;

cout<<"请输入矩阵的行列和非零元素个数:

"<

in>>M>>N>>T;

b.Init(M,N);

if(T>(M*N))

{

cerr<<"输入的元素个数超过范围"<

exit

(1);

}

else

{

cout<<"请输入各非零元素的行数列数和值"<

cout<<"行数列数值"<

for(inti=1;i<=T;i++)//输入元素结点并且插入矩阵

{

cout<<"["<

";

in>>m>>n>>p;

b.Insert(m,n,p);//插入结点

}

returnin;

}

}

ostream&operator<<(ostream&out,Matrix&b)//输出函数重载

{

node*x;

for(inti=1;i<=b.Row;i++)//先确定各行头结点的位置再遍历各行,以输出所有非零元

{

x=b.Locate(i);

x=x->right;

for(intj=1;j<=b.Col;j++)

{

if(x->head==false&&(x->triple.col==j))

{

cout.width(4);

out<triple.value;

x=x->right;

}

elseif(x->head==true)

{

for(j;j<=b.Col;j++){cout.width(4);cout<<"0";}

break;

}

else{cout.width(4);cout<<"0";}

}

cout<

}

returnout;

}

Matrix&Matrix:

:

operator=(Matrix&T)//重载赋值号函数的实现

{

this->Row=T.Row;

this->Col=T.Col;

node*current;

for(inti=1;i<=temp;i++)

{

current=T.Locate(i);

while(current->right!

=current)

{

current=current->right;//通过行遍历逐个赋值

this->Insert(current->triple.row,current->triple.col,current->triple.value);

}

}

return*this;

}

voidMatrix:

:

makeEmpty()//清空矩阵的实现

{

node*del,*current;

for(inti=1;i<=temp;i++)

{

current=Locate(i);//找到列的附加头结点

while(current->down!

=Locate(i))

{

del=current->down;//通过列的附加头结点向下删除结点

current->down=del->down;

deletedel;

}

}

}

MatrixMatrix:

:

Mul(Matrixb)//矩阵乘法的实现

{

if(this->Col==b.Row)

{

MatrixC(this->Row,b.Col);

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 语文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1