分享
 
 
 

和我一起写矩阵类(四)

王朝other·作者佚名  2006-02-01
窄屏简体版  字體: |||超大  

和我一起写矩阵类(四)

大连理工大学软件学院WAKU(转载请保留署名)

这次来写矩阵的运算。先从最简单的开始。

1. 获得矩阵的行和列

template <class T>

int CMatrix<T>::GetM()

{

return m;

}

template <class T>

int CMatrix<T>::GetN()

{

return n;

}

这个。。。一点技术含量都没有不多说了。

2.下标运算符

矩阵的主要数据都是放到二维数组里,在二维数组里我们可以用array[0][0]这种非常直观的形式表示数组里的元素。我们的矩阵要想和用二维数组一样舒服就得重载[]运算符,代码出奇的简单:

template <class T>

T*& CMatrix<T>::operator[](int i)

{

return p[i];

}

天啊!T*&这是什么东西啊?呵呵,觉得是天书就说明你C++没学好,要打PP哦~~

T*是T类型的指针,这没什么疑义吧?&不是取地址符,而是“引用”。引用说白了就是给一个变量起个外号,比如:

int a = 3;

int& b = a;

cout<<b<<endl;

a = 4;

cout<<b<<endl;

程序输出3和4,这里b就是a的外号,除了名字外,a和b是一样的。

既然引用是一个外号,那么所有变量出现的地方都可以换成该变量的引用,函数返回的变量也不例外。现在请跟随我的思路推导一个结论:变量可以赋值->引用是变量的外号,那么也可以给引用赋值->函数可以返回引用,所以也可以给函数的返回值赋值。

比如:

int a = 0;

int& function(){return a;}

void main()

{

function() = 3;

cout<<a<<endl;

}

a是一个全局变量,function函数返回a的引用,那么function() = 3就等价于a = 3,输出3就顺理成章了。

函数放到等号的左边真是要多别扭就有多别扭,不过回到我们的矩阵类上的[]运算符重载你就会发现这种技术是那么亲切。

运算符重载也是一个函数,如果已经定义了名为matrix的矩阵,matrix[0]就相当于调用matrix.operator[](0)这个函数。T*&返回了对p[i]的引用,前面说过p[i]是一个行指针,我们可以用p[0][0]来使用二维数组里的一个元素。如果返回的是p[0]的引用;那么matrix[0][0]就相等于p[0][0],这不就是数组里的第一个元素吗?而且你想让matrix[0][0]出现在等号的哪边都可以,和p[0][0]的用法完全一样。

3.转置

把行变成列,把列变成行的一种运算。

template <class T>

void CMatrix<T>::Transpose()

{

int i, j;

T t;

if (m == n) //方阵

{

for (i = 0; i < m; i++)

{

for (j = i; j < m; j++)

{

t = p[i][j];

p[i][j] = p[j][i];

p[j][i] = t;

}

}

}

else //非方阵

{

CMatrix<T> t(n, m);

for (i = 0; i < m; i++)

{

for (j = 0; j < n; j++)

{

t[j][i] = p[i][j];

}

}

*this = t;

}

}

虽然非方阵的代码完全适合方阵矩阵的转置,不过效率差了很多,多敲几行代码换来效率的提升是非常划算的。所以我分两种情况来实现转置。

对于方阵转置,由于行和列是相等的,所以只需做数值上的交换即可。两个for循环遍历了矩阵的上三角阵,交换p[i][j]和p[j][i]完成转置。由于我们已经重载了[]运算符,所以这里不会有任何问题。

非方阵的转置看起来有点麻烦,首先创建了一个临时的矩阵对象t,并用两个参数的构造函数创建了一个nxm的0矩阵。然后也是两个for循环,用p[i][j]给t[j][i]赋值结束后,t就是矩阵的转置了。

this指针指向了调用此函数的对象,那么*this就代表这个对象,很简单。

=运算符是无论简单类型(int, float)还是自定义的类对象都可以无须定义就可使用的一个运算符,默认的=只是简单的内存块复制,你那个对象有啥,我就一模一样的盗版过来。一般来说,这么做没什么问题,但是一旦数据成员中有指针的时候使用=运算符一定要留心。

还记得我们的动态二维数组吧,就是用T** p表示的那个~~。比如一个矩阵对象名字叫a,它里面的p指向了起始地址为1000的二维数组。这时候我又创建了一个矩阵对象b,并让b=a。由于默认的=会完全复制,造成的结果就是b里面的p也指向了起始地址为1000的二维数组。你改变了a,那b就跟着也被改了,更严重的是,一旦a销毁了,你那个可怜的b还以为自己的日子过的不错。你再使用b的时候,WINDOWS会给你一张很难看的脸。

上段代码的*this = t也有这个毛病,想解决这个问题。就必须重载=号运算符:

template <class T>

void CMatrix<T>::operator=(CMatrix<T>& a)

{

int i, j;

if (p)

{

for (i = 0; i < m; i++)

{

delete[] p[i];

}

delete[] p;

}

m = a.GetM(); n = a.GetN();

p = new T*[m];

for (i = 0; i < m; i++)

{

p[i] = new T[n];

for (j = 0; j < n; j++)

{

p[i][j] = a[i][j];

}

}

}

程序先释放二维数组的空间,然后又申请了一个和引用传递进来的矩阵a一样大小的空间,并用a给对象赋值。这样就复制了一个一模一样的矩阵,而且每个矩阵都有自己的空间,就不会出现冲突的问题了。

这个函数的形参是引用传递的。如果形参是一个对象,使用引用传递可以避免一次拷贝构造函数的调用,从而提供效率,不过要留心对象有可能被更改。

说到拷贝构造函数,就会有和上面类似的问题产生:

CMatrix<int> a(2, 2);

CMatrix<int> b(a);

第二条语句就调用了拷贝构造函数,如果你不提供拷贝构造函数,编译器会为你提供一个,不过这个和默认的=运算符有一样的隐患,所以让我们也把它写出来:

template <class T>

CMatrix<T>::CMatrix(CMatrix<T>& a)

{

int i, j;

m = a.GetM(); n = a.GetN();

p = new T*[m];

for (i = 0; i < m; i++)

{

p[i] = new T[n];

for (j = 0; j < n; j++)

{

p[i][j] = a[i][j];

}

}

}

因为对象创建之间肯定不会占用内存,所以释放内存这步就可以省略,其他的就和=运算符里的一样了。

一个转置牵扯出这么多问题,有点出乎意料吧?但是我们经过自己的努力,一个个的把它们解决掉,这种成就感是无可比拟的。这次就先到这,下次我们会完成最后的加,减和乘法的运算,都是比较简单的。88~~

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有