样版类别-向量和矩阵的定义_第1页
样版类别-向量和矩阵的定义_第2页
样版类别-向量和矩阵的定义_第3页
样版类别-向量和矩阵的定义_第4页
样版类别-向量和矩阵的定义_第5页
已阅读5页,还剩92页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1/97,樣版類別向量和矩陣的定義,向量和矩陣是線性代數和數值分析的基礎。藉由這兩個類別,我們介紹如何建立樣版類別 (template class)。此外,我們還要在本章中討論動態建立和移除物件的語法。,23,2/97,樣版類別向量和矩陣的定義,23.1向量23.2Vector樣版類別23.3矩陣23.4Matrix樣版類別23.5物件陣列的動態創造和刪除23.6常犯的錯誤,3/97,23.1 向量,把向量(vector)定義成物件的好處: 1. 將向量視為獨立的單元。2. 透過運算子重載,將向量運算以最精簡、最接近數學式的方式表達。例如,向量間的加法和內積可以分別簡潔地寫成 V1 + V2和V1 * V2 。,4/97,使用指標定義向量(1/2),考慮線性代數一般的使用習慣,可以犧牲第一個元素不用,而將記憶空間安排為N+1個元素:int N = 5;float* V = new float N+1; 圖示如下:,5/97,使用指標定義向量(2/2),可以使用delete回收不再使用的記憶體 資源。 delete V;,6/97,23.2 Vector樣版類別,定義樣版類別 (class template)。以下是一個 簡化的例子: template /T代表一個尚未決定的資料型態class Vector private: int Size; T* V; public: Vector(int); / 建構函數不使用Vector Vector(Vector,7/97,定義樣版類別 (一個以上的未定類別),定義樣版類別 (一個以上的未定類別) template class Vector / . 其他敘述 ;,8/97,以樣版類別Vector定義物件,分別用來宣告一個整數向量Vi和一個浮點數向量Vd: Vector Vi; Vector Vd;,9/97,成員函數的定義,在實作樣版類別的成員函數時,必需在每個成員函數的定義前都加上template 的宣告。 例如,Vector 的建構函數可以寫成: template Vector:Vector(int N) Size = N; V= new TN+1; return; ,10/97,Vector 的解構函數,template Vector:Vector() delete V; ,11/97,加法operator+() 的重載成員函數,template Vector Vector:operator + (const Vector ,12/97,完整的Vector樣版類別,樣版類別Vector的完整程式寫成檔案Vector.h。這個樣版類別的定義中包括了:建構函數 (constructor)複製建構函數 (copy constructor) 解構函數 (destructor)指派運算子 (assignment operator, =) +、-、*、/等四個運算子 的重載。,13/97,運算子*,在程式Vector.h中,運算子*被重載了三次:(1)純量乘以向量。例如V1 = 2.5 * V2;(2)向量乘以純量。例如V1 = V2 * 2.5;(3)向量的內積。例如double x = V1 * V2;其中 (1)純量乘以向量只能以friend函數寫成,因為運算子的左側運算元不是Vector物件。,14/97,專門用來發出檢查訊息的函數 (1/2),例如,做向量加法前,要檢查兩個向量的長度是否相同。 inline void Check(bool ErrorCondition, const string ,15/97,專門用來發出檢查訊息的函數 (2/2),將判斷式和錯誤訊息以參數的方式傳遞/ 定義加法運算子 operator + ()template Vector Vector:operator+(const Vector,16/97,配置新記憶空間的成員函數,建構函數,複製建構函數,和指派運算子= 都有配置新記憶空間的動作。因此,我們將這個動作 集中寫成inline 函數Create():template void Vector:Create(int N) if(N1) Size = 0; V = 0; else Size = N; V= new TN+1;,17/97,配置新記憶空間,例如,複製建構函數的定義可以比較簡潔地寫成: template Vector:Vector(Vector ,18/97,指派運算子operator = (),指派運算子必需重新定義,因為成員內有指標,而且等號左右兩邊的向量不一定一樣長。指派運算子的定義如下: template Vector Vector:operator=(const Vector ,19/97,重載運算子 (1/2),我們將operator() 的返回資料型態設定為參照。如此一來,它才可以是左值lvalue,也可以是右值rvalue ,例如: V2 = 4.8; float x = V6;,20/97,重載運算子 (2/2),operator () 的inline成員函數定義如下所示: T ,21/97,專門用來顯示向量的函數Display(),template void Vector:Display() for(int i = 1; i = Size; i+) cout setiosflags(ios:right) setiosflags(ios:fixed) setiosflags(ios:showpoint) setprecision(4) setw(12) Vi; cout Size, 索引錯誤, 超過邊界!); return Vi; / 宣告成員函數 Display() void Display();,28/97,範例程式檔案 Vector.h 定義樣版類別Vector的完整程式(7/18),/ 函數 Create() 的定義template void Vector:Create(int N) if(N1) Size = 0; V = 0; else Size = N; V= new TN+1;,29/97,範例程式檔案 Vector.h 定義樣版類別Vector的完整程式(8/18),/ 建構函數的定義template Vector:Vector(int N) Create(N); return; / 解構函數的定義template Vector:Vector() delete V; ,30/97,範例程式檔案 Vector.h 定義樣版類別Vector的完整程式(9/18),/ 複製建構函數的定義-1template Vector:Vector(int N, const T* OldV) Create(N); for (int i=1; i= Size; i+)Vi= OldVi-1; return;,31/97,範例程式檔案 Vector.h 定義樣版類別Vector的完整程式(10/18),/ 複製建構函數的定義-2template Vector:Vector(Vector,32/97,範例程式檔案 Vector.h 定義樣版類別Vector的完整程式(11/18),/ 定義指派運算子 operator = ()template Vector Vector:operator=(const Vector,33/97,範例程式檔案 Vector.h 定義樣版類別Vector的完整程式(12/18),/ 定義加法運算子 operator + ()template Vector Vector:operator+(const Vector,34/97,範例程式檔案 Vector.h 定義樣版類別Vector的完整程式(13/18),/ 定義減法運算子 operator - ()template Vector Vector:operator-(const Vector,35/97,範例程式檔案 Vector.h 定義樣版類別Vector的完整程式(14/18),/ 定義乘法運算子-1 operator * ()template Vector operator*(const T,36/97,範例程式檔案 Vector.h 定義樣版類別Vector的完整程式(15/18),/ 定義乘法運算子-2 operator * ()template Vector operator*(const Vector,37/97,範例程式檔案 Vector.h 定義樣版類別Vector的完整程式(16/18),/ 定義乘法運算子-3 operator * ()template T Vector:operator*(const Vector,38/97,範例程式檔案 Vector.h 定義樣版類別Vector的完整程式(17/18),/ 定義成員函數 Display()template void Vector:Display() for(int i = 1; i = Size; i+) cout setiosflags(ios:right) setiosflags(ios:fixed) setiosflags(ios:showpoint) setprecision(4) setw(12) Vi; cout endl; return;,39/97,範例程式檔案 Vector.h 定義樣版類別Vector的完整程式(18/18),/ 定義除法運算子 operator / ()template Vector Vector:operator/(const T #endif,40/97,範例程式檔案TestVector.cpp(1/6),分別使用Vector 和Vector 去宣告包含int和double兩種資料型態元素的向量:DV1、DV2、IV1和IV2,並驗證向量除以浮點數、向量間加法和向量內積的正確性。我們也藉由DVb1、DVb2 和DVb3 驗證了索引運算子。,41/97,範例程式檔案TestVector.cpp(2/6),/ TestVector.cpp#include Vector.hint main () double Ddata1=2, 0.5, 4.6; double Ddata2=4, 6.5, 3.8; int Idata1=2, 5, 6; int Idata2=4, 65, 38;,42/97,範例程式檔案TestVector.cpp(3/6),Vector DV1(3, Ddata1); Vector DV2(3, Ddata2), DVa(3), DVb(3); Vector IV1(3, Idata1); Vector IV2(3, Idata2), IVa(3), IVb(3); int Idot; double Ddot; cout : endl; cout DV1 的值是: endl;,43/97,範例程式檔案TestVector.cpp(4/6),DV1.Display(); cout DV2 的值是: endl; DV2.Display(); DVa=DV1+DV2; cout (DV1 + DV2) 的值是: endl; DVa.Display(); DVb=DV1/2.0;cout (DV1/2.0) 的值是: endl;,44/97,範例程式檔案TestVector.cpp(5/6),cout : endl; cout IV1 的值是: endl;,45/97,範例程式檔案TestVector.cpp(6/6),IV1.Display(); cout IV2 的值是: endl; IV2.Display(); IVa=IV1+IV2; cout (IV1 + IV2)的值是: endl; IVa.Display(); IVb=IV1/2.0; cout (IV1/2.0) 的值是: endl; IVb.Display(); Idot = IV1*IV2; cout IV1 和 IV2 的內積是 : Idot endl; return 0;,46/97,程式執行結果(1/2),-測試 Vector: DV1 的值是: 2.0000 0.5000 4.6000 DV2 的值是: 4.0000 6.5000 3.8000 (DV1 + DV2) 的值是: 6.0000 7.0000 8.4000 (DV1/2.0) 的值是: 1.0000 0.2500 2.3000 DV1 和 DV2 的內積是 : 28.7300-,47/97,程式執行結果(2/2),測試 Vector: IV1 的值是: 2 5 6 IV2 的值是: 4 65 38 (IV1 + IV2)的值是: 6 70 44 (IV1/2.0) 的值是: 1 2 3 IV1 和 IV2 的內積是 : 561,48/97,23.3 矩陣,二維陣列稱為矩陣(matrix)。 向量的外積(outer product) 也會產生矩陣。 矩陣內的單一行或單一列抽離出來也可形成向量。,49/97,使用指標定義矩陣(1/7),以動態配置的方式在執期間設定矩陣語法有兩種: (1)將各列在記憶體中獨立設定 int M = 3; int N = 4; float* A = new float *M; for (int i=0; iM; i+) Ai = new float N;,50/97,使用指標定義矩陣(2/7),將各列在記憶體中獨立設定 相當於在記憶中動態配置了圖23.3.1中所示的指標和記憶空間:,圖23.3.1二維陣列的動態記憶體配置,51/97,使用指標定義矩陣(3/7),回收指令為 :for (int i=0; i M; i+) delete Aidelete A;,52/97,使用指標定義矩陣(4/7),將各列在記憶體中連續配置 int M = 3; int N = 4; float* A = new float *M; A0 = new float M*N; for (int i=1; iM; i+) Ai = Ai-1 + N;,53/97,使用指標定義矩陣(5/7),將各列在記憶體中連續配置A也是指標陣列的指標,但指標陣列的元素A0,A1 和A2 各指向同一個一維陣列的不同位址,圖23.3.2二維陣列A的儲存方式及相關的指標,54/97,使用指標定義矩陣(6/7),這種配置方式的回收指令為: delete A0 delete A;將索引的預設表示法修正為慣用的表示法 int M = 3; int N = 4; Float* A = new float *M+1; A0 = new float M*N+1; A1 = A0; for (int i = 2; i = M; i+) Ai = Ai-1 + N;,55/97,使用指標定義矩陣(7/7),將索引的預設表示法修正為慣用的表示法,圖23.3.3符合習慣的二維陣列A的連讀儲存方式及相關的指標,56/97,23.4 Matrix樣版類別,Matrix樣版類別的建構函數 為了使用上的方便,基本上所有向量和矩陣的初始值都是以一維陣列的形式給予。 例如: double W1=2.1, 0.5, 3.2, 6.4, 8.2, 4.9; Matrix M1(2,3, W1);,57/97,定義Matrix樣版類別的建構函數,template Matrix:Matrix(int Row, int Col, const T* V) Create(Row,Col); for(int i = 1; i = M; i+) for(int j = 1; j = N ; j+) Aij=V(i-1)*Col+(j-1); return;,58/97,配置矩陣空間的成員函數Create(),這個成員函數在處理前先進行參數檢查的動作:emplate void Matrix:Create(int Row, int Col) Check(Row1)|(Col1), 矩陣建構錯誤, 行列大小不能為負值!); M = Row; N = Col; A = new T* M+1; A0= new TM*N+1; A1= A0; for(int i=2; i= M; i+) Ai=Ai-1+N;,59/97,重載運算子 ,方便使用索引(index) 來存取矩陣元素。例如: M32 = 4.8; float x = M46; 雖然矩陣元素有兩個下標,我們並不需要重新定義兩重索引運算子。因為每一個一維陣列的元素都可以經由預設的索引運算子得到。,60/97,重載第一重索引運算子operator (),T* operator(int i)return Ai; 它的返回資料型態是指標T*。,61/97,矩陣和向量之間互相轉換的成員函數,我們將13.5節的函數PickRow()和SetCol()修改成樣版類別的成員函數SetCol()和PickCol()。成員函數SetCol()用來將某個向量所有元素的值複製到矩陣裏面某一個選定的行裏面。成員函數PickCol()將矩陣的某一行所有元素的值複製出來成為一個新的向量。,62/97,定義成員函數 PickCol(),template Vector Matrix:PickCol(int I) Vector TempV(M); for (int i=1; i= M; i+) TempVi= AiI; return TempV;,63/97,定義成員函數 SetCol(),template void Matrix:SetCol(int j, Vector,64/97,範例程式檔案 Matrix.h (樣版類別Matrix的完整定義)(1/16),/ Matrix.h#ifndef Matrix_H#define Matrix_H#include #include using namespace std;,65/97,範例程式檔案 Matrix.h (樣版類別Matrix的完整定義)(2/16),/ = 宣告 Matrix 樣版類別 =template class Matrix private: int M, N;T* A; void Create(int, int); public:/ 宣告建構函數 Matrix(int, int); Matrix(int, int, const T*);,66/97,範例程式檔案 Matrix.h (樣版類別Matrix的完整定義)(3/16),/ 宣告複製建構函數 Matrix(Matrix,67/97,範例程式檔案 Matrix.h (樣版類別Matrix的完整定義)(4/16),/ 宣告乘法運算子 operator * () Matrix operator*(const Matrix,68/97,範例程式檔案 Matrix.h (樣版類別Matrix的完整定義)(5/16),/ = 成員函數的定義 =/ 函數 Create() 的定義template void Matrix:Create(int Row, int Col) Check(Row1)|(Col1), 矩陣建構錯誤, 行列大小不能為負值!); M = Row; N = Col; A = new T* M+1; A0= new TM*N+1;,69/97,範例程式檔案 Matrix.h (樣版類別Matrix的完整定義)(6/16),A1= A0; for(int i=2; iMatrix:Matrix(int Row, int Col) Create(Row,Col); return;,70/97,範例程式檔案 Matrix.h (樣版類別Matrix的完整定義)(7/16),/ 建構函數的定義 (從一維陣列建立二維陣列)template Matrix:Matrix(int Row, int Col, const T* V) Create(Row,Col); for(int i = 1; i = M; i+) for(int j = 1; j = N ; j+) Aij=V(i-1)*Col+(j-1); return;,71/97,範例程式檔案 Matrix.h (樣版類別Matrix的完整定義)(8/16),/ 複製建構函數的定義template Matrix:Matrix(Matrix,72/97,範例程式檔案 Matrix.h (樣版類別Matrix的完整定義)(9/16),/ 解構函數的定義template Matrix:Matrix() delete A0; delete A;,73/97,範例程式檔案 Matrix.h (樣版類別Matrix的完整定義)(10/16),/ 定義指派運算子 operator = ()template MatrixMatrix:operator=(const Matrix,74/97,範例程式檔案 Matrix.h (樣版類別Matrix的完整定義)(11/16),/ 定義加法運算子 operator + ()template MatrixMatrix:operator+(const Matrix,75/97,範例程式檔案 Matrix.h (樣版類別Matrix的完整定義)(12/16),/ 定義乘法運算子 operator * ()template MatrixMatrix:operator*(const Matrix j+),76/97,範例程式檔案 Matrix.h (樣版類別Matrix的完整定義)(13/16), temp.Aij=0.0; for(int k = 1; k void Matrix:Display(),77/97,範例程式檔案 Matrix.h (樣版類別Matrix的完整定義)(14/16), cout setiosflags(ios:right) setiosflags(ios:fixed) setiosflags(ios:showpoint) setprecision(4); for (int i = 1; i = M; i+) for(int j = 1; j = N ; j+) cout setw(10) Aij ; cout endl; return;,78/97,範例程式檔案 Matrix.h (樣版類別Matrix的完整定義)(15/16),/ 定義成員函數 PickCol()template Vector Matrix:PickCol(int I) Vector TempV(M); for (int i=1; i= M; i+) TempVi= AiI; return TempV;,79/97,範例程式檔案 Matrix.h (樣版類別Matrix的完整定義)(16/16),/ 定義成員函數 SetCol()template void Matrix:SetCol(int j, Vector#endif,80/97,範例程式檔案TestVM.cpp (1/5),我們分別驗證了兩個矩陣間的加法和乘法的正確性。此外,由於要使用SetCol() 和PickCol() 這兩個成員函數,這個程式必需在開頭處以 #include Vector.h #include Matrix.h我們可以由這個簡單的範例發現,使用自訂的樣版類別Vector和Matrix可以大大地簡化主程式的撰寫。而且樣版類別一旦建構完成,可以應用到各式各樣的問題,非常方便。,81/97,範例程式檔案TestVM.cpp (2/5),/ TestVM.cpp#include Vector.h#include Matrix.h#include #include using namespace std;,82/97,範例程式檔案TestVM.cpp (3/5),int main () double W1=2.1, 0.5, 3.2, 6.4, 8.2, 4.9; double W2=4.6, 6.5, 3.6, 4.2, 5.8, 9.4; double W3=2.1, 3.2, 9.8, 6.9, 2.4, 1.6; double w1=2, 0.5; double w2=4, 6.5; Matrix M1(2,3, W1); Matrix M2(2,3, W2); Matrix M3(3,2, W3); Matrix Ma(2,3), Mb(2,2); Vector V1(2, w1); Vector V2(2, w2), Xa(3), Xb(3);,83/97,範例程式檔案TestVM.cpp (4/5),cout M1 是: endl; M1.Display(); cout M2 是: endl; M2.Display(); cout M3 是: endl; M3.Display(); Ma=M1+M2; cout (M1+M2) 是 : endl; Ma.Display(); Mb=M1*M3;,84/97,範例程式檔案TestVM.cpp (5/5),cout (M1*M3) 是 : endl; Mb.Display(); V2 = M1.PickCol(2); cout M1 的第2行是: endl; V2.Display(); cout V1 是: endl; V1.Display(); M1.SetCol(3,V1); cout 將 M1 的第3行設為 V1 後n M1 變成為: endl; M1.Display(); return 0;,85/97,程式執行結果(1/2),M1 是: 2.1000 0.5000 3.2000 6.4000 8.2000 4.9000 M2 是: 4.6000 6.5000 3.6000 4.2000 5.8000 9.4000 M3 是: 2.1000 3.2000 9.8000 6.9000 2.4000 1.6000 (M1+M2) 是 : 6.7000 7.0000 6.8000 10.6000 14.0000 14.3000,86/97,程式執行結果(2/2),(M1*M3) 是 : 16.9900 15.2900 105.5600 84.9000 M1 的第2行是: 0.5000 8.2000 V1 是: 2.0000 0.5000 將 M1 的第3行設為 V1 後 M1 變成為: 2.1000 0.5000 2.0000 6.4000 8.2000 0.5000,87/97,23.5 物件陣列的動態創造和刪除,對於一維陣列而言, int* pV = new int200; 能夠在記憶堆上配置出能夠裝得下200個int資料的空間。 回收這個記憶空間的指令: delete pV;這就是包裝在樣版類別Vector的成員函數Create() 和解構函數 Vector() 內的主耍內容。,88/97,物件陣列的動態創造和刪除,如果自訂的類別名稱是MyClass,則動態產生和回收200個物件的語法和基本資料型態的語法一致的。例如 MyClass* pA = new MyClass 200;至於回收記憶空間的語法也和基本資料型態相同 (注意,這個時候中括號 不可以省略): delete pA;,89/97,範例程式檔案 VectorCD.h(1/6),改寫23.2節樣版類別Vector的定義,成為標頭檔VectorCD.h,讓每一次建構函數和解構函數被呼叫時都會對外顯示訊息,並加上兩個static資料成員:CountConst和CountDist,以分別計算建構函數和解構函數被呼叫的次數。至於其它的運算子重載部份則暫時移除,讓程式更加精簡。,90/97,範例程式檔案 VectorCD.h(2/6),/ VectorCD.h#ifndef VectorCD_H#define Vector

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论