和我一起写矩阵类(一)
和我一起寫矩陣類(一)
?
?
?
?
?
?
?
?
?
?
?
大連理工大學(xué)軟件學(xué)院WAKU(轉(zhuǎn)載請(qǐng)保留署名)
最近Mr.Zeng的一個(gè)作業(yè)就是自己實(shí)現(xiàn)一個(gè)矩陣類,這是一個(gè)非常有實(shí)用價(jià)值的類。我花了幾天完成了,期間也增長了很多知識(shí),不敢獨(dú)享,拿出來和大家共同學(xué)習(xí)。由于本人水平很非常有限,有錯(cuò)誤不要給我面子,請(qǐng)盡快指出,我將不勝感激!!
開始吧。
矩陣也是一種數(shù)據(jù)結(jié)構(gòu),所以在設(shè)計(jì)之前一定要明確有哪些數(shù)據(jù)和哪些操作。首先,最容易想到的,矩陣要有一個(gè)一個(gè)二維數(shù)組,好這簡單:
double array[3][3];
?
?
?
?
?
?
?
先等一下,為什么是double類型的?為什么是3x3的二維數(shù)組,如果圖省事,這么定義當(dāng)然可以,而且在相當(dāng)一部分場合中,這個(gè)矩陣類也很實(shí)用。
我們要有更高的追求,要想辦法使我們的類壽命更長。改進(jìn)它:
類型用模板,可以花最少的時(shí)間最大程度上的提高代碼的重用性。
?
?
?
?
?
?
?
template?<class?T>
?
?
?
?
?
?
?
那么二維數(shù)組應(yīng)該幾乘幾的呢,答案是由用戶確定。數(shù)組在矩陣使用的時(shí)候動(dòng)態(tài)創(chuàng)建,可大可小,最具有靈活性。那么動(dòng)態(tài)的二維數(shù)組應(yīng)如何表示呢?大家都動(dòng)態(tài)創(chuàng)建過一維數(shù)組,寫過類似這樣的語句:
int *p = new int[10];
?
?
?
?
?
?
?
new關(guān)鍵字動(dòng)態(tài)的申請(qǐng)了10個(gè)int類型的連續(xù)空間,并把這段連續(xù)空間的首地址賦給指針p。然后就可以使用p[i]來引用數(shù)組元素,因?yàn)閿?shù)組名就是指針。以此類推,動(dòng)態(tài)二維數(shù)組也應(yīng)該用指針來表示、來引用元素。在定義指針之前,還是回顧一下二維數(shù)組的一些概念,舉例說明:
double array[3][3];
?
?
?
?
?
?
?
定義了3x3的double型數(shù)組,由于內(nèi)存是線性的,所以這9個(gè)元素在內(nèi)存中都是“一條直線”似的存放。array[0][0]是頭一個(gè)元素,array[2][2]是最后一個(gè)元素,這很好理解。那么array[0]代表什么?它是什么東西?
?
?
?
?
?
?
?
它其實(shí)也是個(gè)指針,指向數(shù)組的第一行元素的行首。同理array[1]是第二行行首指針,array[2]是第三行。array呢?它是數(shù)組名,那肯定也是個(gè)指針,但是它可不是我們常用的那種指針,而是一個(gè)指向指針的指針(二級(jí)指針)。它指向的是“指向第一行行首的指針”。看著像一個(gè)繞口令,仔細(xì)琢磨一下就明白了。如果你感興趣,輸入以下代碼并執(zhí)行:
double array[3][3];
?
?
?
?
?
?
?
cout<<&array[0]<<endl <<array<<endl;
?
?
?
?
?
?
?
你會(huì)發(fā)現(xiàn)輸出的值是完全相同的,這就證明了array指向了array[0]。總結(jié)一下就是:
想表示或引用幾維數(shù)組,就需要幾級(jí)指針。
?
?
?
?
?
?
?
那么我們的類屬性的聲明就差不多了:
template <class T>
?
?
?
?
?
?
?
class CMatrix
?
?
?
?
?
?
?
{
?
?
?
?
?
?
?
??? int m;???? //行數(shù)
?
?
?
?
?
?
?
??? int n;???? //列數(shù)
?
?
?
?
?
?
?
??? T** p;???? //二維數(shù)組指針
?
?
?
?
?
?
?
};
?
?
?
?
?
?
?
由于是動(dòng)態(tài)創(chuàng)建的數(shù)組,所以矩陣的行和列各需要用一個(gè)int型變量來記錄。p就是用模板創(chuàng)建的二級(jí)指針,來表示二維數(shù)組。
下一次我們就開始類方法的設(shè)計(jì)。大家覺得我寫的還可以,麻煩貴手輕抬回一下貼,讓我知道有人在看,好有動(dòng)力寫下去,謝謝~~
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?和我一起寫矩陣類(二)
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
上次說到了在構(gòu)造函數(shù)和SetMatrix函數(shù)中用數(shù)組給矩陣賦值,兩個(gè)函數(shù)的第三個(gè)形參都是T* array。用這種方式傳遞二維數(shù)組應(yīng)該說有點(diǎn)無奈,我們以前學(xué)過的傳遞二維數(shù)組都是類似以下形式:
?
?
?
void function(int a[][10]);
?
?
?
數(shù)組的最高維一定要是一個(gè)常數(shù),但是我們的矩陣的大小是不定的,不能確定各個(gè)維的大小,那怎么辦?不要忘了,所有數(shù)組在內(nèi)存中都是線性的,我們可以用一個(gè)一級(jí)指針來引用任意維的數(shù)組。看以下示例代碼:
?
?
?
void main()
?
?
?
{
?
?
?
??? int a[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
?
?
?
??? int *p = (int*)a;
?
??? cout<<p[3]<<endl;?
?
?
}
?
?
?
程序工作良好,并如你所愿,輸出了4。這就說明一級(jí)指針也是可以引用二維數(shù)組的。如果我想用指針p引用原數(shù)組里的元素a[1][1]就需要做一個(gè)簡單的變換p[1*3 + 1] 即p[4],這就是為什么給p[i][j]賦值的時(shí)候用array[i*n + j]了。n即為二維數(shù)組的列數(shù)。
?
?
?
但是和上面示例的第二條語句一樣,構(gòu)造函數(shù)CMatrix(int m, int n, T* array)和SetMatrix(int m, int n, T* array)函數(shù)在調(diào)用的時(shí)候都需要把二維數(shù)組的數(shù)組名強(qiáng)制轉(zhuǎn)換成一級(jí)指針。調(diào)用形式如下:
?
?
?
double array[2][2] = {1, 2, 3, 4};
?
?
?
CMatrix<double>?? matrix(2, 2, (double*)array);
?
?
?
或者
?
?
?
double array[2][2] = {1, 2, 3, 4};
?
?
?
CMatrix<double>?? matrix;
?
?
?
matrix.SetMatrix(2, 2, (double*)array);
?
?
?
這樣就定義了一個(gè)2行2列名為matrix的矩陣對(duì)象,并且矩陣?yán)锩娴闹岛投S數(shù)組array一樣。
?
?
?
下面我們完成最后一個(gè)SetMatrix函數(shù),在用構(gòu)造函數(shù)CMatrix(int m, int n)創(chuàng)建對(duì)象后,如果只想用一個(gè)數(shù)組填充矩陣而不改變行列值,就可以用下面的函數(shù):
?
?
?
template <class T>
?
?
?
void CMatrix<T>::SetMatrix(T* array)
?
?
?
{
?
?
?
??? int i, j;
?
??? if (p)?
?
?
??? {
?
?
?
?????? for (i = 0; i < this->m; i++)
?
?
?
?????? {
?
?
?
?????????? delete[] p[i];
?
?
?
?????? }
?
?
?
?????? delete[] p;
?
?
?
??? }
?
?
?
?
?
?
??? for (i = 0; i < m; i++)
?
?
?
??? {
?
?
?
?????? for (j = 0; j < n; j++)
?
?
?
?????? {
?
?
?
?????????? p[i][j] = array[i*n+j];
?
?
?
?????? }
?
?
?
}
?
?
?
}
?
?
?
沒什么新東西就不詳細(xì)講解了。
?
?
?
至此,矩陣創(chuàng)建和初始化的相關(guān)函數(shù)基本上都已經(jīng)完成了,如果你勤快,你的類聲明應(yīng)該是這個(gè)樣子的:
?
?
?
template <class T>
?
?
?
class CMatrix
?
?
?
{
?
?
?
??? int m;???? //行數(shù)
?
?
?
??? int n;???? //列數(shù)
?
?
?
??? T** p;???? //二維數(shù)組指針
?
?
?
public:
?
?
?
??? CMatrix(void);
?
?
?
??? CMatrix(int m, int n);?????????
?
?
?
??? CMatrix(int m, int n, T* array);
?
?
?
??? ~CMatrix(void);
?
?
?
??? void SetMatrix(int m, int n);
?
?
?
??? void SetMatrix(int m, int n, T* array);
?
?
?
??? void SetMatrix(T* array);
?
?
?
};
?
?
?
怎么樣?大家還能跟上吧?有什么問題盡管問,我能答的肯定會(huì)回答。下次我們開始寫矩陣運(yùn)算的函數(shù),并對(duì)我做的時(shí)候遇到的問題進(jìn)行詳細(xì)討論。敬請(qǐng)期待~
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
和我一起寫矩陣類(三)
?
?
?
大連理工大學(xué)軟件學(xué)院WAKU(轉(zhuǎn)載請(qǐng)保留署名)
?
?
?
?
?
?
類的方法(也可叫做成員函數(shù))從構(gòu)造函數(shù)開始,我寫的一個(gè)構(gòu)造函數(shù)是這樣的:
template <class T>
?
?
?
?
?
?
?
CMatrix<T>::CMatrix(void)
?
?
?
?
?
?
?
{
?
?
?
?
?
?
?
??? m = 0; n? = 0;
?
?
?
?
?
?
?
??? p = NULL;
?
?
?
?
?
?
?
}
?
?
?
?
?
?
?
由于使用了模板,所以在每個(gè)成員函數(shù)之前都要加上template <class T>,而且類名后一定要加上<T>,否則會(huì)編譯出錯(cuò)。這是一個(gè)無參的構(gòu)造函數(shù),里面把行列值賦0,把數(shù)組的指針置為空,這是一個(gè)好習(xí)慣。除了安全帶來的另一個(gè)好處是避免了定義對(duì)象數(shù)組時(shí)寫出一長串的初始化表。
?
?
?
?
?
?
?
如果有可能定義類的對(duì)象數(shù)組,最好提供類的無參構(gòu)造函數(shù)
?
?
?
?
?
?
?
然后再提供另外的成員函數(shù)完成有參構(gòu)造函數(shù)所完成的功能。我寫的一個(gè)有參構(gòu)造函數(shù)是:
?
?
?
?
?
?
?
template <class T>
?
?
?
?
?
?
?
CMatrix<T>::CMatrix(int m, int n)
?
?
?
?
?
?
?
{
?
?
?
?
?
?
?
??? int i, j;
?
??? p = new T*[m];?
?
?
?
?
?
?
??? for (i = 0; i < m; i++)
?
?
?
?
?
?
?
??? {
?
?
?
?
?
?
?
?????? p[i] = new T[n];
?
?
?
?
?
?
?
?????? for (j = 0; j < n; j++)
?
?
?
?
?
?
?
?????? {
?
?
?
?
?
?
?
?????????? p[i][j] = 0;
?
?
?
?
?
?
?
?????? }
?
?
?
?
?
?
?
??? }
?
?
?
?
?
?
?
??? this->m = m; this->n = n;
?
?
?
?
?
?
?
}
?
?
?
?
?
?
?
這是有參構(gòu)造函數(shù)所完成的功能,無參構(gòu)造函數(shù)由于不知道行列的具體值所以不能加入以上代碼,所以我們必須要另寫一個(gè)一模一樣的函數(shù)“補(bǔ)充”這個(gè)功能:
?
?
?
?
?
?
?
template <class T>
?
?
?
?
?
?
?
void CMatrix<T>::SetMatrix(int m, int n)
?
?
?
?
?
?
?
{
?
?
?
?
?
?
?
??? int i, j;
?
??? p = new T*[m];?
?
?
?
?
?
?
??? for (i = 0; i < m; i++)
?
?
?
?
?
?
?
??? {
?
?
?
?
?
?
?
?????? p[i] = new T[n];
?
?
?
?
?
?
?
?????? for (j = 0; j < n; j++)
?
?
?
?
?
?
?
?????? {
?
?
?
?
?
?
?
?????????? p[i][j] = 0;
?
?
?
?
?
?
?
?????? }
?
?
?
?
?
?
?
??? }
?
?
?
?
?
?
?
??? this->m = m; this->n = n;
?
?
?
?
?
?
?
}??
?
這兩段代碼實(shí)現(xiàn)了動(dòng)態(tài)創(chuàng)建 m 行 n 列二維數(shù)組的功能。 p = new T*[m]; 語句和第一篇里創(chuàng)建一維數(shù)組的語句非常類似,這里申請(qǐng)了有 m 個(gè) T 類型的指針數(shù)組(即數(shù)組里存放的全是指向 T 類型的指針),并把這個(gè)數(shù)組的首地址賦給了 p 。然后外層 for 循環(huán)遍歷數(shù)組里的每一個(gè)指針,并用每個(gè)指針 p[i] 接收由 new 創(chuàng)建的 n 個(gè) T 類型數(shù)組。?
?
?
?
?
?
?
明白前面我講過二維數(shù)組,這段代碼也就很好理解,p[i]是一個(gè)行指針,p[0]相當(dāng)于double array[3][3]里的array[0]、p[1]就相當(dāng)于array[1];然后每個(gè)行指針又“管轄”著剛申請(qǐng)的n個(gè)元素。里層for循環(huán)把這一行的元素值初始為0。其實(shí)說穿了也很簡單吧。
?
?
?
?
?
?
?
下面把析構(gòu)函數(shù)完成,很簡單,就是釋放申請(qǐng)的空間:
?
?
?
?
?
?
?
template <class T>
?
?
?
?
?
?
?
CMatrix<T>::~CMatrix(void)
?
?
?
?
?
?
?
{
?
?
?
?
?
?
?
??? int i;????
?
?
?
?
?
?
?
??? if (p)
?
?
?
?
?
?
?
??? {
?
?
?
?
?
?
?
?????? for (i = 0; i < m; i++)
?
?
?
?
?
?
?
?????? {
?
?
?
?
?
?
?
?????????? delete[] p[i];
?
?
?
?
?
?
?
?????? }
?
?
?
?
?
?
?
?????? delete[] p;
?
?
?
?
?
?
?
??? }
?
?
?
?
?
?
?
}
?
?
?
?
?
?
?
記住一點(diǎn),有幾個(gè)new就要有幾個(gè)delete。另外注意一點(diǎn),delete后面的[]一定不要落下,否則編譯器并不會(huì)報(bào)錯(cuò),你的內(nèi)存卻還照樣泄漏。
矩陣?yán)锩嬗幸粋€(gè)二維數(shù)組,那么一個(gè)可以把二維數(shù)組填充到到矩陣?yán)锏暮瘮?shù)無疑是非常有用的。讓我們實(shí)現(xiàn)它吧:
template <class T>
?
?
?
?
?
?
?
CMatrix<T>::CMatrix(int m, int n, T* array)
?
?
?
?
?
?
?
{
?
?
?
?
?
?
?
??? int i, j;??
?
??? p = new T*[m];?
?
?
?
?
?
?
??? for (i = 0; i < m; i++)
?
?
?
?
?
?
?
??? {
?
?
?
?
?
?
?
?????? p[i] = new T[n];
?
?
?
?
?
?
?
?????? for (j = 0; j < n; j++)
?
?
?
?
?
?
?
?????? {
?
?
?
?
?
?
?
?????????? p[i][j] = array[i*n+j];
?
?
?
?
?
?
?
?????? }
?
?
?
?
?
?
?
??? }
?
?
?
?
?
?
?
??? this->m = m; this->n = n;
?
?
?
?
?
?
?
}
?
?
?
?
?
?
?
這是一個(gè)構(gòu)造函數(shù),用于在創(chuàng)建對(duì)象時(shí)就用二維數(shù)組賦值,對(duì)應(yīng)重載的SetMatrix函數(shù)如下:
?
?
?
?
?
?
?
template <class T>
?
?
?
?
?
?
?
void CMatrix<T>::SetMatrix(int m, int n, T* array)
?
?
?
?
?
?
?
{
?
?
?
?
?
?
?
??? int i, j;
?
??? if (p)?
?
?
?
?
?
?
??? {
?
?
?
?
?
?
?
?????? for (i = 0; i < this->m; i++)
?
?
?
?
?
?
?
?????? {
?
?
?
?
?
?
?
?????????? delete[] p[i];
?
?
?
?
?
?
?
?????? }
?
?
?
?
?
?
?
?????? delete[] p;
?
?
?
?
?
?
?
??? }??
?
??? p = new T*[m];?
?
?
?
?
?
?
??? for (i = 0; i < m; i++)
?
?
?
?
?
?
?
??? {
?
?
?
?
?
?
?
?????? p[i] = new T[n];
?
?
?
?
?
?
?
?????? for (j = 0; j < n; j++)
?
?
?
?
?
?
?
?????? {
?
?
?
?
?
?
?
?????????? p[i][j] = array[i*n+j];
?
?
?
?
?
?
?
?????? }
?
?
?
?
?
?
?
??? }
?
?
?
?
?
?
?
??? this->m = m; this->n = n;
?
?
?
?
?
?
?
}
?
?
?
?
?
?
?
由于調(diào)用SetMatrix函數(shù)時(shí)的對(duì)象有可能已經(jīng)申請(qǐng)了空間,所以再數(shù)組賦值之前應(yīng)該釋放掉。
?
?
?
?
?
?
?
我們不是要傳遞二維數(shù)組嗎?為什么第三個(gè)參數(shù)是T* array?這不是一個(gè)一級(jí)指針嗎?不覺得賦值的時(shí)候用p[i][j] = array[i*n+j];這種語句很奇怪嗎?請(qǐng)聽下回分解
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
總結(jié)
以上是生活随笔為你收集整理的和我一起写矩阵类(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。