今天c程序设计课的内容是要求我们封装矩阵的一些运算,然后突然想到前段时间做过关于大整数类的问题,就想着能不能依葫芦画瓢的做一个矩阵类。
尝试了大半个晚上,感觉还是可行的,重载了输入输出赋值和一些简单的矩阵运算(细节没有处理的很好,使用的时候可能会出现一些小bug),至于矩阵的逆运算,特征值还有秩感觉比较复杂,所以暂时还没有深入地去做。
和大整数类一样,我们一段一段的进行编译:
首先是构造函数,和矩阵的一些特征:
//行和列,data表示用于存放每个单位值的数组
int row,col,data[100][100];
//构造函数
Square(){
}
Square(const Square&x) {
*this=x;}
Square(const string&x) {
*this=x;}
接下来是重载赋值运算符。由于课上的实验你可以自拟矩阵的行和列,但更多时候是直接给你一个未知行和列长度的矩阵,那我们怎么得到矩阵的行和列呢?
我们在split那一章的时候,学习了getline的运用,于是这里用getline的第二个用法:将整个矩阵视作一个字符串,q为这个字符串的结束,然后以回车符为分割符得到每一行的字符串,再对每一行字符串用空格作分割符得到每一个字符串,再将字符串转化为一个一个的数字。
代码如下:
Square &operator=(const string &x){
int row1=0,col1=0;
//这是上次提到的切割字符串的方法
string p; stringstream streamR(x);
while (getline(streamR,p)){
//先按照回车切割
row1++;col1=0;
stringstream streamQ(p);string s;
while (getline(streamQ,s,' ')){
//再按照空格切割得到的即是一个一个数字
col1++;data[row1][col1]=0;
int sign=(s[0]=='-');//字符串转化为数字,判断第一位是否为0
for (int i=s.size()-1,j=1;i>=0+sign;i--,j*=10) data[row1][col1]+=j*((int)s[i]-48);
data[row1][col1]*=sign?-1:1;
}
}
row=row1; col=col1;
return *this;
}
(我可以用ssprintf转化字符串,我就是不用。哎,就是玩儿!)
接下来是重载输入和输出的运算符,需要注意的是,重载输入运算符时,需要用getline处理istream:
//重载输入符
friend istream &operator>>(istream &in,Square &x){
string str; getline(in,str,'q');
x=str.c_str(); return in;
}
//重载输出运算符
friend ostream &operator<<(ostream &out,Square &x){
for (int i=1;i<=x.row;i++){
for (int j=1;j<=x.col;j++){
out<<x.data[i][j]<<" ";}
out<<endl;
}
return out;
}
(这里的输出其实是有一些问题的,应该要转化为字符串的)
做到这里,我们已经可以做简单的输入和输出了:
接下来就该做运算符了,首先是加法:
//+运算符,只有行数列数相同的矩阵才可以相加,不然会显示出错了
Square operator+(const Square &b) const{
if (b.row==row&&b.col==col){
Square C;C.row=row;C.col=col;
for (int i=1;i<=C.row;i++)
for (int j=1;j<=C.col;j++) C.data[i][j]=b.data[i][j]+data[i][j];
return C;
}
else cout<<"出错了";
如果你认真的阅读过大整数类的那里的代码,领略过那里的思想,我相信矩阵的加法对你是非常简单的(我相信你没有)。
减法:
//-运算符
Square operator-(const Square &b) const{
if (b.row==row&&b.col==col){
Square C;C.row=row;C.col=col;
for (int i=1;i<=C.row;i++)
for (int j=1;j<=C.col;j++) C.data[i][j]=-b.data[i][j]+data[i][j];
return C;
}
else cout<<"出错了";
}
乘法相对而言会特殊一点,不过也不会特殊的太多,只需要遵循线性代数的计算法则即可:
//*运算符,需要注意的是可以相乘的两个矩阵,左行需要等于右列
//得到的矩阵的行数等于右边矩阵的行数,列数为左边矩阵的列数
Square operator*(const Square &b) const{
if (b.row==col){
Square C;C.row=row;C.col=b.col;
for (int i=1;i<=C.row;i++){
for (int j=1;j<=C.col;j++){
C.data[i][j]=0;
for (int k=1;k<=col;k++) C.data[i][j]+=data[i][k]*b.data[k][j];
}
}
return C;
}
else cout<<"出错了";
}
还有一个转置函数:
//转置
Square rev()const{
Square C;C.row=col;C.col=row;
for (int i=1;i<=C.row;i++)
for (int j=1;j<=C.col;j++) C.data[i][j]=data[j][i];
return C;
}
以上的代码都是可以拿来直接使用的,不过比较可惜的是,一方面是因为时间比较仓促,另一方面是我对于c++类的操作并不熟练,导致上面的代码可能会有一些用的不顺畅的地方(基本是输出的时候,我输出那里偷懒了)或者小bug:
比如说这里,由于我的getline是以q为终止符的,导致输入q换行的时候,换行符会被计入下一个矩阵中,导致出错,那我是怎么处理的呢?
所以最后的最后,还是希望大家能够指出我代码的bug。如果知道上面的代码有什么加快运算的方法,或者对处理矩阵的逆运算,秩,特征值有想法的,欢迎大家一起交流学习啊。(我是five)