矩阵操作C++

矩阵操作C++
矩阵操作C++

淮阴工学院

算法设计技能训练

设计题目:矩阵操作(动态数组)

院别:计算机与软件工程学院

专业:计算机科学与技术

班级: XXXXXXXXXX

学生姓名: XXX 学号: XXXXXXXXXX

指导教师: XXX XXX

2017 年11 月

算法设计技能训练成绩

班级:计算机1161

学生姓名: XXX 学号:1161301105 院别:计算机与软件工程学院

算法设计技能训练题目:矩阵操作(动态数组)

教师签字:

日期:

目录

1 引言 (1)

1.1课题描述 (1)

1.2课题意义 (1)

1.3设计思想 (1)

2 总体设计 (2)

2.1总体功能结构 (2)

2.2类的分析与设计 (2)

3 详细设计和实现 (3)

3.1构建m*n的全零矩阵 (3)

3.2构建n*n的方阵 (3)

3.3拷贝构造函数(深拷贝) (3)

3.4根据一维数组拷贝函数 (3)

3.5根据二维数组拷贝函数 (3)

3.6析构函数 (4)

3.7矩阵转置 (4)

3.8矩阵信息获取及修改 (4)

3.9矩阵加法 (4)

3.10矩阵减法 (4)

3.11矩阵乘法 (5)

3.12重载=运算符 (5)

3.13打印函数 (5)

4 系统测试 (5)

4.1主界面 (5)

4.2创建矩阵 (6)

4.3矩阵相加 (8)

4.4矩阵相减 (8)

4.5矩阵数乘 (9)

4.6矩阵转置 (9)

4.6矩阵相乘 (9)

结论 (11)

致谢 (12)

参考文献 (13)

附录 (14)

1 引言

1.1课题描述

设计矩阵操作类算法,并做到可以动态的操作不同类型的数组,矩阵操作包括各种类型的构造函数如直接构造m*n型的全零矩阵或者全零方阵或者根据一

维数组二维数组来构造矩阵,然后是析构函数。还需要返回行数列数以及设置某一位置的值和返回某一位置的值,操作类主要包括矩阵的转置、加减乘除和数乘赋值功能还有打印功能

1.2课题意义

矩阵是线性代数研究的主要对象。矩阵是由来源于某一问题的有关的数据所组成的矩形数表,在对矩阵定义了一些重要的运算并逐渐形成了矩阵的理论体系后,矩阵成为对数学研究即应用非常有效的数学工具,矩阵计算的理论与方法在许多实际问题研究中有着广泛的应用。将矩阵用代码实现可以大大减少实际计算工作量,使人们在生活研究方面得到很大的便利,省时省力。

1.3设计思想

本算法主要设计一个Matrix的类来实现矩阵的各种操作。该矩阵操作的数据类型可以自己选择,因为采用了模板,相对的设计时也会稍微繁琐一些。矩阵数据成员主要有矩阵元素的头指针,矩阵行数rowNum,矩阵列数colNum。公有成员函数则要实现各种方式的构造函数如直接构造m*n型的全零矩阵或者全零

方阵或者根据一维数组二维数组来构造矩阵。获得矩阵信息的功能如获得矩阵的行数列数获得矩阵某一位置的值打印矩阵等。还有修改矩阵某一位置的值的功能,再接下来是最重要的矩阵的各种操作包括加减乘和数乘还有转置等,这些主要通过重载运算符来实现。

2 总体设计

2.1总体功能结构

2.1.1数据成员包括

矩阵类所开辟的空间的头指针item、矩阵行数rowNum、矩阵列数colNum。

2.1.2主要功能包括

在这里采用C++语言实现一个可动态分配的矩阵类,类中包括一些简单的运算等操作具体要求如下:

(1)使用构造函数完成矩阵的初始化赋值(动态内存分配);

(2)使用拷贝构造函数完成矩阵复制的深拷贝;

(3)使用析构函数完成矩阵动态内存的释放;

(4)使用函数实现两个矩阵的和;

(5)使用函数实现两个矩阵的差;

(6)使用函数实现两个矩阵的积;

(7)使用函数求矩阵的数乘;

(8)使用函数实现矩阵的转置;

(9)编写一个主函数测试上述功能。

2.2类的分析与设计

根据实验要求,设计Matrix类,头文件主要有

,,,除了矩阵所开辟的空间的头指针和矩阵行数列数为类的私有成员其余均为类的公有成员。因为用了模板所以实现时要注意格式对应,每个函数在类外定义时记得在前面加一句template ,里面的类型定义如果是要设计矩阵内部元素的都用T来代替,然后返回类型还有形参如果是Matrix的话记得在后面加

3 详细设计和实现

3.1构建m*n的全零矩阵

构造时注意容错率,当m,n的输出出错时可以进行提醒并重新输入,输入正确行数m和列数n,item开辟一个新的大小为m*n的空间,空间的数据类型因为使用了模板可以根据使用者的要求进行变换。矩阵的所有元素在空间是按行依次线性排列的。通过for循环将所有数据成员赋值为零。

3.2构建n*n的方阵

构造时注意容错率,当n的输出出错时可以进行提醒并重新输入,输入正确n,item开辟一个新的大小为n*n的空间,空间的数据类型因为使用了模板可以根据使用者的要求进行变换。方阵的所有元素在空间是按行依次线性排列的。通过for循环将所有数据成员赋值为零。

3.3拷贝构造函数(深拷贝)

这里采用深拷贝,而不是直接复制值的浅拷贝,因为浅拷贝直接复制指针的地址,这样会导致两个矩阵共用一个空间即两个矩阵其实是同一个矩阵,其中一个变了另一个也会跟着变。浅拷贝缺点太多,所以这里采用创建一个新的空间把值全部复制过来的深拷贝。空间的类型因为有模板可以根据需要随意更改。

3.4根据一维数组拷贝函数

因为矩阵的空间里的数据也是线性排列的,所以只要提供一维数组的行数和列数信息就可以实现把一维数组所包含的矩阵复制到数据成员空间中。item根据类型需要开辟空间,然后通过for循环将数组成员复制过去,最后给数据成员行数和列数值就可以了。

3.5根据二维数组拷贝函数

因为矩阵最常见的形式是二维数组,所以也需要通过二位数组来构造矩阵,不过一般以二维数组为形参的话数组的第二个纬度一定要先设置好值,这样就无法实现动态的构造各种规模的矩阵。所以这里采用另一种方法,就是数组转化为指针的指针。除了形参为指针的指针,在赋值的时候记得把数组强制转化一下就可以了,这样就可以动态构造任意类型的矩阵了

3.6析构函数

因为只创建了一个连续的数组空间所以比较简单,直接delete就好了。

3.7矩阵转置

转置函数主要实现将矩阵的行列进行对换,所以赋值时注意把数据成员的行数和列数对调,这里的操作是返回转置后的对象,所以注意this的使用,赋值时是第i行第j列换成第j行第i列,返回类型是Matrix。

3.8矩阵信息获取及修改

返回行数列数比较简单,直接return对应值就好了。返回某一矩阵的值则注意位置对应关系,i和j都是从0开始的,所以对应关系是i*colNum+j。加上const 是为了防止对原数据造成未知的修改。

设置某一位置的值也要注意对应关系,对应关系上面已经分析过了都是一样的为i*colNum+j。虽然加了模板,但是修改时还是只能改成原矩阵的数据类型,模板主要在创建的时候起作用。

3.9矩阵加法

加法函数这里使用对加法运算符重载的形式,矩阵加法必须两个行列数要相同否则不能相加,所以这里使用if语句进行判断,如果不想等就只返回原矩阵。这里没有开辟新空间所以是对加法运算符前面的那个矩阵的空间进行操作,所以待会用等号运算符后,不仅等号前面的矩阵变了,加法前面的矩阵也会变而且两者是相同的。把每个元素重新设置成相加后的值然后返回就好了,注意位置对应关系不要搞错了就好了。

3.10矩阵减法

减法函数通过对减法运算符的重载来实现。使用时也要用if语句来判断两个矩阵是否能相减,不能则返回原矩阵。同样的,减法也是在减法运算符的前面的矩阵空间里进行操作,通过for循环将每个对应位置的值算好然后赋值给这个空间的对应位置,因为前面已经有了get()set()等函数所以接下来的操作都会方便很多。同样当用x=y-x时,y也随着变了,而且y的值和x的值是一样的。

3.11矩阵乘法

3.11.1矩阵间相乘

矩阵间的乘法则是要求左边矩阵的列数等于右边矩阵的行数,这样乘积才有意义。所以开始就要用if语句来判断两个矩阵是否符合条件,不符合则输出无法相乘,符合则进行计算。创建的新矩阵行数列数应为相乘后的行列数,然后通过for

循环按照矩阵运算的法则进行计算并将得出值赋给对应位置。最后返回该矩阵。

3.11.2矩阵的数乘

数乘相对来说要简单一些,基本操作和上述都差不多,不用开辟新的矩阵,直接在原矩阵上操作就好了,将所有值都乘以输入的数再放回去就好了,最后返回矩阵。

3.12重载=运算符

重载=运算符,执行该运算符时要先判断原矩阵是否存在,如果存在就删除掉原矩阵。重新创建一个和后面矩阵行列数对应的矩阵,然后将对应的值赋值过去,然后返回this指针即可。

3.13打印函数

打印函数要用到格式化输出,所以头文件要包括,用setw()函数来每

个输出的数所占的字节数,来达到对齐的目的,经过比较数字还是右对齐比较好看所以使用setiosflags(ios::right)来使输出的数都在所占字节的最右边。每输出一行,用endl换行。

4 系统测试

4.1主界面

图4-2-1

该main函数用于测试功能,但在编写过程中遇到了不少问题,还好在于永涛老师的帮助下都解决了。首先我限制了最多只能创建两个矩阵,继续往下创建的话变化的都是第二个矩阵,因为只是简单的实现一下函数的功能。使用456功能时默认是对第一个矩阵使用,所以不用将要使用该功能的矩阵创建在第二个。4.2创建矩阵

图4-2-2

主界面输入1后会显示这个画面,显示有四种创建数组的方式,这四种方式会在这里一一展示,不过待会的运算操作主要用的是34两种方式。

4.2.1m*n的零矩阵

图4-2-3

图4-2-4

输入1后再根据提示输入行数和列数,就可以得到对应的零矩阵

4.2.2n*n的零方阵

图4-2-5

图4-2-6

输入2后根据提示输入方阵的维度就可以创建对应的零方阵了。

4.2.3一维数组构建矩阵

图4-2-7

图4-2-8

输入1然后再输入3进入一维数组创建矩阵功能,根据提示依次输入矩阵行数和列数,然后从左到右从上到下依次输入就能成功创建该矩阵,并且该矩阵会被打印出来方便检查是否有错。

4.2.4二维数组构建矩阵

图4-2-9

图4-2-10

输入1在输入3进入二维数组创建矩阵功能,根据提示依次输入矩阵行数和列数,然后从左到右从上到下依次输入就能成功创建该矩阵,输入后屏幕同样会把该矩阵打印出来方便检查是否有错。

4.3矩阵相加

这里的相加就用上面34构造出来的矩阵

图4-2-11

4.4矩阵相减

因为上面已经执行过相加了,所以矩阵1就变成结果的那个矩阵了

图4-2-12

4.5矩阵数乘

图4-2-13

图4-2-14

输入5后显示要被数乘的矩阵,然后按照提示输入要乘的数,屏幕就会打印出结果了,而且原函数也已经变成数乘后的结果了。

4.6矩阵转置

该main函数的转置功能是把转置功能打印出来,并没有改变原函数的原值。

图4-2-15

4.6矩阵相乘

因为那两个构建的矩阵不符合矩阵相乘的要求,所以要重新构建两个,根据矩阵

相乘的规则,第一个矩阵的的列要和第二个矩阵的行相同,输入完两个矩阵后在主界面输入4屏幕就会依次打印出矩阵1和矩阵2还有相乘后的结果并且第一个矩阵会变成相乘后的结果。

图4-2-16

经测试,函数的功能都能顺利实现。

结论

矩阵操作需要扎实的c++基础,因为里面涉及到各个方面的操作,同时设计该算法也是对过去知识一次很好的巩固。在这里有好几个个人认为比较重要的点需要注意,第一个是模板,使用了模板无疑加大了代码的难度,但也提高了代码的适用性,可以处理多种类型的数据,使用模板时要注意每个函数前要加template ,然后当要返回的类型或者使用的形参是Matrix类时,后面都要加上,再函数里面开辟新空间时要类型换成T,类似这样的都要注意到,否则一

个不小心代码就会发生错误。第二个是动态的创建数组以及将之拷贝到矩阵类中,这里面主要要处理的问题是一般数组定义需要确定的空间,而我们是为了实现动态构造数组,就不能使用那种方法,所以我用指针的方法来构造,因为矩阵的物理储存结构是线性有规律的,所以可以通过指针的位移来进行赋值操作,形参要把指针类型。第三个是main函数里的问题,在实现时发现在对象还未定义前就在下面进行使用是会出现问题的,所以这个时候要把前面的定义换成用指针类new一个对象,在主函数前就先定义好指针,这样才能完成在case语句中写入

语句操作还未定义的对象。还有就是用了指针之后操作运算符时都要用指针形式来操作如*a = *a + *b。所以熟悉了二维数组和指针还有类之间的关系,才能完成这次的课程设计。

致谢

在这一周的算法技能设计训练里,多亏了于长辉老师和高丽老师的指导还有同学们的帮助,是老师们一丝不苟的工作作风和耐心的讲解,我才能理解算法,并知道自己这一周要做什么怎么做。在这里最要感谢的大一的c++老师于永涛,在我每次遇到困难无法解决时是他一直细心的指导着我,并且每一次都能帮我完美解决。所以这个设计不是我一个人的成果,有了大家的无私帮助,我才能顺利的完成这次的算法设计。

参考文献

1 郑振杰.C++程序设计北京:人民邮电出版社,2005

2 柴欣.C/C++程序设计河北大学出版社,2002

3 余苏宁、王明福.C++程序设计北京:高等教育出版社,2003

4 吕凤翥.C++语言程序设计(第2版).电子工业出版社,2007.2

5 李云清、杨庆红、揭安全.数据结构[M].人民邮电大学出版社,2004.6

6 Marshall P. Cline and Greg A. Lomow, C++ FAQs, Addison-Wesley, 1995

7 Bruce Eckel, Thinking in C++(C++ 编程思想,刘宗田等译),机械工业出版社,2000

8 Steve Maguire, Writing Clean Code(编程精粹,姜静波等译),电子工业出版社,1993

9 Scott Meyers, Effective C++, Addison-Wesley, 1992

10 Robert B. Murry, C++ Strategies and Tactics, Addison-Wesley, 1993

11 Steve Summit, C Programming FAQs, Addison-Wesley, 1996

附录

#include

#include

#include

using namespace std;

template

class Matrix

{

T *item; //指向矩阵的第一个元素

int rowNum; //矩阵行数

int colNum; //矩阵列数

public:

Matrix(int m, int n); //构建m*n的全零矩阵

Matrix(int n); //构建一个n*n的全零方阵

Matrix(const Matrix &x); //拷贝构造函数(深拷贝)

Matrix(T *items, int m, int n); //根据一维数组拷贝函数

Matrix(T **items, int m, int n); //根据二维数组拷贝函数

~Matrix(); //析构函数

Matrix Trans() const; //将矩阵转置

void set(int i, int j, T value); //设置矩阵某一位置值

int getRow() const { return rowNum;} //返回行数

int getCol() const { return colNum;} //返回列数

T get(int i, int j) const { return item[i*colNum + j]; } //返回某一位置的值Matrix operator +(const Matrix &m); //两个矩阵相加

Matrix operator -(const Matrix &m); //两个矩阵相减

Matrix operator *(const Matrix &m); //两个矩阵相乘

Matrix operator *(const T f); //矩阵乘以常数

Matrix& operator=(const Matrix& m);

void print(); //打印矩阵

};

template

Matrix::Matrix(int m, int n)

{

if(m<0||n<0)

{

cerr<<"矩阵大小不能为负";

exit(1);

}

rowNum = m;

colNum = n;

item = new T[m*n];

for(int i=0; i

item[i] = 0;

}

template

Matrix::Matrix(int n)

{

if(n<0)

{

cerr<<"矩阵大小不能为负";

exit(1);

}

rowNum = n;

colNum = n;

item = new T[n*n];

for(int i=0; i

item[i] = 0;

}

template

Matrix::Matrix(const Matrix &x) {

rowNum = x.rowNum;

colNum = x.colNum;

item = new T[rowNum*colNum];

for(int i=0; i

}

template

Matrix::Matrix(T *items, int m, int n) {

item = new T[m*n];

for(int i=0; i

{

item[i] = items[i];

}

rowNum = m;

colNum = n;

}

template

Matrix::Matrix(T **items, int m, int n) {

item = new T[m*n];

rowNum = m;

colNum = n;

for(int i=0; i

for(int j=0; j

item[i*n+j] = items[i][j];

cout<

}

template

void Matrix::print()

{

for(int i=0; i

{

cout<

if((i+1)%colNum==0)

cout<

}

}

template

Matrix::~Matrix()

{

delete []item;

}

template

void Matrix::set(int i, int j, T value)

{

item[i*colNum+j] = value;

}

template

Matrix Matrix::operator +(const Matrix &m)

{

if (m.colNum != colNum || m.rowNum != rowNum) return *this;

Matrix _copy = *this;

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

{

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

{

_copy.set(i, j, get(i, j) + m.get(i, j));

}

}

return _copy;

}

template

Matrix Matrix::operator -(const Matrix &m)

{

if (m.colNum != colNum || m.rowNum != rowNum) return *this;

Matrix _copy = *this;

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

{

相关主题
相关文档
最新文档