《精品样版类别向量和矩阵的定义》由会员分享,可在线阅读,更多相关《精品样版类别向量和矩阵的定义(98页珍藏版)》请在金锄头文库上搜索。
1、樣版類別向量和矩陣的定義樣版類別向量和矩陣的定義 向量和矩陣是線性代數和數值分析的基向量和矩陣是線性代數和數值分析的基礎。藉由這兩個類別,我們介紹如何建礎。藉由這兩個類別,我們介紹如何建立樣版類別立樣版類別(templateclass)(templateclass)。此外,我。此外,我們還要在本章中討論動態建立和移除物們還要在本章中討論動態建立和移除物件的語法。件的語法。 231樣版類別向量和矩陣的定義樣版類別向量和矩陣的定義n n23.1向量n n23.2Vector樣版類別n n23.3矩陣n n23.4Matrix樣版類別n n23.5物件陣列的動態創造和刪除n n23.6常犯的錯誤22
2、3.1 向量向量 把向量(vector)定義成物件的好處: 1.將向量視為獨立的單元。2. 透過運算子重載,將向量運算以最精簡、最接近數學式的方式表達。例如,向量間的加法和內積可以分別簡潔地寫成V1+V2和V1*V2。3使用指標定義向量使用指標定義向量(1/2)(1/2)n n 考慮線性代數一般的使用習慣,可以犧牲第一考慮線性代數一般的使用習慣,可以犧牲第一個元素不用,而將記憶空間安排為個元素不用,而將記憶空間安排為N+1N+1個元素:個元素:intN=5;float*V=newfloatN+1; 圖示如下:圖示如下:4使用指標定義向量使用指標定義向量(2/2)可以使用delete回收不再使用
3、的記憶體資源。deleteV; 523.2 Vector樣版類別樣版類別 n n定義樣版類別定義樣版類別(classtemplate)(classtemplate)。以下是一個。以下是一個簡化的例子:簡化的例子: template/template/T T代表一個尚未決定的資料型態代表一個尚未決定的資料型態classVectorclassVector private:private:intSize;intSize;T*V;T*V;public:public:Vector(int);/Vector(int);/建構函數不使用建構函數不使用VectorVectorVector(Vector&);/
4、Vector(Vector&);/類別名稱以類別名稱以VectorVector表示表示Vector();/Vector();/解構函數不使用解構函數不使用VectorVector;6定義樣版類別定義樣版類別 (一個以上的未定類別一個以上的未定類別)n n定義樣版類別定義樣版類別 ( (一個以上的未定類別一個以上的未定類別) ) templatetemplateclassVectorclassVector /./.其他敘述其他敘述 ;7以樣版類別以樣版類別Vector定義物件定義物件n n分別用來宣告一個整數向量分別用來宣告一個整數向量ViVi和一個浮點數向和一個浮點數向量量VdVd: Vect
5、orVi;VectorVi;VectorVd;VectorVd; 8成員函數的定義成員函數的定義 在在實實作作樣樣版版類類別別的的成成員員函函數數時時,必必需需在在每每個個成成員員函函數數的的定義前都加上定義前都加上templatetemplate的宣告。的宣告。 例如,例如,VectorVector的建構函數可以寫成:的建構函數可以寫成: templatetemplateVector:Vector(intN)Vector:Vector(intN)Size=N;Size=N;V=newTN+1;V=newTN+1;return;return;9Vector 的解構函數的解構函數 templat
6、etemplateVector:Vector()deleteV;Vector:Vector()deleteV; 10加法加法operator+() 的重載成員函數的重載成員函數 templatetemplateVectorVector:operator+VectorVector:operator+(constVector&V2)(constVector&V2)VectorTemp(Size);VectorTemp(Size);for(inti=1;i=Size;i+)for(inti=1;i=Size;i+)Temp.Vi=Vi+V2.Vi;Temp.Vi=Vi+V2.Vi;returnTem
7、p;returnTemp;11完整的完整的Vector樣版類別樣版類別樣版類別樣版類別VectorVector的完整程式寫成檔案的完整程式寫成檔案Vector.hVector.h。這個樣版類別的定義中包括了:這個樣版類別的定義中包括了:建構函數建構函數(constructor)(constructor)複製建構函數複製建構函數(copyconstructor)(copyconstructor) 解構函數解構函數(destructor)(destructor)指派運算子指派運算子(assignmentoperator,=)(assignmentoperator,=) + +、- -、* *、/
8、/等四個運算子等四個運算子 的重載。的重載。 12運算子運算子* * 在程式在程式Vector.hVector.h中,運算子中,運算子* *被重載了三次:被重載了三次:(1)(1)純量乘以向量。純量乘以向量。 例如例如V1=2.5*V2;V1=2.5*V2;(2)(2)向量乘以純量。向量乘以純量。 例如例如V1=V2*2.5;V1=V2*2.5;(3)(3)向量的內積。向量的內積。例例如如doubledoublexx=V1V1*V2;*V2;其中其中(1)(1)純量乘以向量只能以純量乘以向量只能以friendfriend函數寫成,函數寫成,因為運算子的左側運算元不是因為運算子的左側運算元不是V
9、ectorVector物件。物件。 13專門用來發出檢查訊息的函數專門用來發出檢查訊息的函數 (1/2) 例如,做向量加法前,要檢查兩個向量的長度是否例如,做向量加法前,要檢查兩個向量的長度是否相同。相同。 inlinevoidCheck(boolErrorCondition,inlinevoidCheck(boolErrorCondition,conststring&Message=Requirementconststring&Message=Requirementfailed)failed) if(ErrorCondition)cerrMessageif(ErrorCondition)ce
10、rrMessageendl;exit(1);endl;exit(1);14專門用來發出檢查訊息的函數專門用來發出檢查訊息的函數 (2/2) (2/2)將判斷式和錯誤訊息以參數的方式傳遞將判斷式和錯誤訊息以參數的方式傳遞/定義加法運算子定義加法運算子operator+()operator+()templatetemplateVectorVector:operator+(constVector&VectorVector:operator+(constVector&V2)V2) Check(Size!=V2.Size,Check(Size!=V2.Size,加法運算錯誤加法運算錯誤,長度不相同長度不
11、相同!);!);VectorTemp(Size);VectorTemp(Size);for(inti=1;i=Size;i+)for(inti=1;i=Size;i+)Temp.Vi=Vi+V2.Vi;Temp.Vi=Vi+V2.Vi;returnTemp;returnTemp; 15配置新記憶空間的成員函數配置新記憶空間的成員函數 n n建構函數,複製建構函數,和指派運算子建構函數,複製建構函數,和指派運算子= =都有配置新記憶空間的動作。因此,我們將這個動作都有配置新記憶空間的動作。因此,我們將這個動作 集中寫成集中寫成inlineinline函數函數Create()Create():te
12、mplatetemplatevoidVector:Create(intN)voidVector:Create(intN) if(N1)if(N1)Size=0;V=0;Size=0;V=0;elseelseSize=N;V=newTN+1;Size=N;V=newTN+1; 16配置新記憶空間配置新記憶空間 n n例如,複製建構函數的定義可以比較簡潔地寫成:例如,複製建構函數的定義可以比較簡潔地寫成:templatetemplateVector:Vector(Vector&OldV)Vector:Vector(Vector&OldV)Create(OldV.Size);Create(OldV.
13、Size);for(inti=1;i=Size;i+)for(inti=1;i=Size;i+)Vi=OldV.Vi;Vi=OldV.Vi;return;return;17指派運算子指派運算子operator = ()n n指派運算子必需重新定義,因為成員內有指標,指派運算子必需重新定義,因為成員內有指標,而且等號左右兩邊的向量不一定一樣長。指派運而且等號左右兩邊的向量不一定一樣長。指派運算子的定義如下:算子的定義如下: templatetemplateVectorVector:operator=(constVector&VectorVector:operator=(constVector&V
14、2)V2)if(Size!=V2.Size)if(Size!=V2.Size)Create(V2.Size);Create(V2.Size);for(inti=1;i=Size;i+)for(inti=1;iSize,Check(iSize,索引錯誤索引錯誤,超過邊界超過邊界!);!);returnVi;returnVi; 20專門用來顯示向量的函數專門用來顯示向量的函數Display() templatetemplatevoidVector:Display()voidVector:Display() for(inti=1;i=Size;i+)for(inti=1;i=Size;i+)cout
15、setiosflags(ios:right)coutsetiosflags(ios:right)setiosflags(ios:fixed)setiosflags(ios:fixed)setiosflags(ios:showpoint)setiosflags(ios:showpoint)setprecision(4)setprecision(4)setw(12)Vi;setw(12)Vi;coutendl;coutendl;return;return; 21範例程式檔案範例程式檔案 Vector.h 定義樣版類定義樣版類別別Vector的完整程式的完整程式(1/18)/Vector.h/Vec
16、tor.h#ifndefVector_H#ifndefVector_H#defineVector_H#defineVector_H#include#include#include#includeusingnamespacestd;usingnamespacestd; inlinevoidCheck(boolErrorCondition,inlinevoidCheck(boolErrorCondition,conststring&Message=Requirementconststring&Message=Requirementfailed)failed)22範例程式檔案範例程式檔案 Vecto
17、r.h 定義樣版類定義樣版類別別Vector的完整程式的完整程式(2/18) if(ErrorCondition)if(ErrorCondition)cerrMessageendl;exit(1);cerrMessageendl;exit(1); /=Vector/=Vector樣版類別樣版類別 =templatetemplateclassVectorclassVector /宣告乘法運算子宣告乘法運算子-1operator*()-1operator*()friendVectoroperator*(constT&,constfriendVectoroperator*(constT&,const
18、Vector&);Vector&);/宣告乘法運算子宣告乘法運算子-2operator*()-2operator*()23範例程式檔案範例程式檔案 Vector.h 定義樣版類定義樣版類別別Vector的完整程式的完整程式(3/18)friendVectoroperator*(constfriendVectoroperator*(constVector&,constT&);Vector&,constT&);private:private:intSize;intSize;T*V;T*V;inlinevoidCreate(int);inlinevoidCreate(int);public:publ
19、ic:/宣告建構函數宣告建構函數Vector(int);Vector(int);Vector(int,constT*);Vector(int,constT*);24範例程式檔案範例程式檔案 Vector.h 定義樣版類定義樣版類別別Vector的完整程式的完整程式(4/18)/宣告複製建構函數宣告複製建構函數Vector(Vector&);Vector(Vector&);/宣告解構函數宣告解構函數Vector();Vector();/Operators/Operators/宣告指派運算子宣告指派運算子operator=()operator=()Vectoroperator=(constVect
20、or&);Vectoroperator=(constVector&);/宣告加法運算子宣告加法運算子operator+()operator+()Vectoroperator+(constVector&);Vectoroperator+(constVector&);/宣告減法運算子宣告減法運算子operator-()operator-()25範例程式檔案範例程式檔案 Vector.h 定義樣版類定義樣版類別別Vector的完整程式的完整程式(5/18)Vectoroperator-(constVector&);Vectoroperator-(constVector&);/宣告乘法運算子宣告乘法運
21、算子-3operator*()-3operator*()Toperator*(constVector&);Toperator*(constVector&);/宣告除法運算子宣告除法運算子operator/()operator/()Vectoroperator/(constT&);Vectoroperator/(constT&);/宣告索引運算子宣告索引運算子operator()operator()T&operator(inti)T&operator(inti)26範例程式檔案範例程式檔案 Vector.h 定義樣版類定義樣版類別別Vector的完整程式的完整程式(6/18) Check(iSi
22、ze,Check(iSize,索引錯誤索引錯誤,超過邊界超過邊界!);!);returnVi;returnVi;/宣告成員函數宣告成員函數Display()Display()voidDisplay();voidDisplay();27範例程式檔案範例程式檔案 Vector.h 定義樣版類定義樣版類別別Vector的完整程式的完整程式(7/18)/函數函數Create()Create()的定義的定義templatetemplatevoidVector:Create(intN)voidVector:Create(intN) if(N1)if(N1)Size=0;V=0;Size=0;V=0;els
23、eelseSize=N;V=newTN+1;Size=N;V=newTN+1; 28範例程式檔案範例程式檔案 Vector.h 定義樣版類定義樣版類別別Vector的完整程式的完整程式(8/18)/建構函數的定義建構函數的定義templatetemplateVector:Vector(intN)Create(N);Vector:Vector(intN)Create(N);return;return;/解構函數的定義解構函數的定義templatetemplateVector:Vector()deleteV;Vector:Vector()deleteV; 29範例程式檔案範例程式檔案 Vector
24、.h 定義樣版類定義樣版類別別Vector的完整程式的完整程式(9/18)/複製建構函數的定義複製建構函數的定義-1-1templatetemplateVector:Vector(intN,constT*OldV)Vector:Vector(intN,constT*OldV) Create(N);Create(N);for(inti=1;i=Size;i+)for(inti=1;i=Size;i+)Vi=OldVi-1;Vi=OldVi-1;return;return; 30範例程式檔案範例程式檔案 Vector.h 定義樣版類定義樣版類別別Vector的完整程式的完整程式(10/18)/複製
25、建構函數的定義複製建構函數的定義-2-2templatetemplateVector:Vector(Vector&OldV)Vector:Vector(Vector&OldV) Create(OldV.Size);Create(OldV.Size);for(inti=1;i=Size;i+)for(inti=1;i=Size;i+)Vi=OldV.Vi;Vi=OldV.Vi;return;return; 31範例程式檔案範例程式檔案 Vector.h 定義樣版類定義樣版類別別Vector的完整程式的完整程式(11/18)/定義指派運算子定義指派運算子operator=()operator=()
26、templatetemplateVectorVector:operator=(constVectorVector:operator=(constVector&V2)Vector&V2) if(Size!=V2.Size)if(Size!=V2.Size)Create(V2.Size);Create(V2.Size);for(inti=1;i=Size;i+)for(inti=1;i=Size;i+)Vi=V2.Vi;Vi=V2.Vi;return*this;return*this; 32範例程式檔案範例程式檔案 Vector.h 定義樣版類定義樣版類別別Vector的完整程式的完整程式(12/
27、18)/定義加法運算子定義加法運算子operator+()operator+()templatetemplateVectorVector:operator+(constVector&VectorVector:operator+(constVector&V2)V2) Check(Size!=V2.Size,Check(Size!=V2.Size, 加法運算錯誤加法運算錯誤,長度不相同長度不相同!);!); VectorTemp(Size);VectorTemp(Size);for(inti=1;i=Size;i+)for(inti=1;i=Size;i+)Temp.Vi=Vi+V2.Vi;Tem
28、p.Vi=Vi+V2.Vi;returnTemp;returnTemp; 33範例程式檔案範例程式檔案 Vector.h 定義樣版類定義樣版類別別Vector的完整程式的完整程式(13/18)/定義減法運算子定義減法運算子operator-()operator-()templatetemplateVectorVector:operator-(constVector&V2)VectorVector:operator-(constVector&V2) Check(Size!=V2.Size,Check(Size!=V2.Size,減法運算錯誤減法運算錯誤,長度不相同長度不相同!);!);Vecto
29、rTemp(Size);VectorTemp(Size);for(inti=1;i=Size;i+)for(inti=1;i=Size;i+)Temp.Vi=Vi-V2.Vi;Temp.Vi=Vi-V2.Vi;returnTemp;returnTemp; 34範例程式檔案範例程式檔案 Vector.h 定義樣版類定義樣版類別別Vector的完整程式的完整程式(14/18)/定義乘法運算子定義乘法運算子-1operator*()-1operator*()templatetemplateVectoroperator*(constT&f,constVectoroperator*(constT&f,c
30、onstVector&V1)Vector&V1) VectorTemp(V1.Size);VectorTemp(V1.Size);for(inti=1;i=V1.Size;i+)for(inti=1;i=V1.Size;i+)Temp.Vi=f*V1.Vi;Temp.Vi=f*V1.Vi;returnTemp;returnTemp; 35範例程式檔案範例程式檔案 Vector.h 定義樣版類定義樣版類別別Vector的完整程式的完整程式(15/18)/定義乘法運算子定義乘法運算子-2operator*()-2operator*()templatetemplateVectoroperator*(
31、constVector&V1,Vectoroperator*(constVector&V1,constT&f)constT&f) VectorTemp(V1.Size);VectorTemp(V1.Size);for(inti=1;i=V1.Size;i+)for(inti=1;i=V1.Size;i+)Temp.Vi=f*V1.Vi;Temp.Vi=f*V1.Vi;returnTemp;returnTemp; 36範例程式檔案範例程式檔案 Vector.h 定義樣版類定義樣版類別別Vector的完整程式的完整程式(16/18)/定義乘法運算子定義乘法運算子-3operator*()-3ope
32、rator*()templatetemplateTVector:operator*(constVector&V2)TVector:operator*(constVector&V2) Check(Size!=V2.Size,Check(Size!=V2.Size,內積運算錯誤內積運算錯誤,長度不相同長度不相同!);!);TProduct=0;TProduct=0;for(inti=1;i=Size;i+)for(inti=1;i=Size;i+)Product+=Vi*V2.Vi;Product+=Vi*V2.Vi;returnProduct;returnProduct; 37範例程式檔案範例程
33、式檔案 Vector.h 定義樣版類定義樣版類別別Vector的完整程式的完整程式(17/18)/定義成員函數定義成員函數Display()Display()templatetemplatevoidVector:Display()voidVector:Display() for(inti=1;i=Size;i+)for(inti=1;i=Size;i+)coutsetiosflags(ios:right)coutsetiosflags(ios:right)setiosflags(ios:fixed)setiosflags(ios:fixed)setiosflags(ios:showpoint)
34、setiosflags(ios:showpoint)setprecision(4)setprecision(4)setw(12)Vi;setw(12)Vi;coutendl;coutendl;return;return; 38範例程式檔案範例程式檔案 Vector.h 定義樣版類定義樣版類別別Vector的完整程式的完整程式(18/18)/定義除法運算子定義除法運算子operator/()operator/()templatetemplateVectorVector:operator/(constT&f)VectorVector:operator/(constT&f) VectorTemp(S
35、ize);VectorTemp(Size);for(inti=1;i=Size;i+)for(inti=1;i=Size;i+)Temp.Vi=Vi/f;Temp.Vi=Vi/f;returnTemp;returnTemp; #endif#endif 39範例程式檔案範例程式檔案TestVector.cpp(1/6)n n 分別使用分別使用VectorVector 和和VectorVector 去宣告包去宣告包含含intint和和doubledouble兩種資料型態元素的向量:兩種資料型態元素的向量:DV1DV1、DV2DV2、IV1IV1和和IV2IV2,並驗證向量除以浮點數、向量間加法和向
36、量,並驗證向量除以浮點數、向量間加法和向量內積的正確性。我們也藉由內積的正確性。我們也藉由DVb1DVb1、DVb2DVb2和和DVb3DVb3驗驗證了索引運算子證了索引運算子 。 40範例程式檔案範例程式檔案TestVector.cpp(2/6)/TestVector.cpp/TestVector.cpp#includeVector.h#includeVector.h intmain()intmain() doubleDdata1=2,0.5,4.6;doubleDdata1=2,0.5,4.6;doubleDdata2=4,6.5,3.8;doubleDdata2=4,6.5,3.8;in
37、tIdata1=2,5,6;intIdata1=2,5,6;intIdata2=4,65,38;intIdata2=4,65,38;41範例程式檔案範例程式檔案TestVector.cpp(3/6) Vector DV1(3, Ddata1);Vector DV1(3, Ddata1);Vector DV2(3, Ddata2), DVa(3), DVb(3);Vector DV2(3, Ddata2), DVa(3), DVb(3); Vector IV1(3, Idata1); Vector IV1(3, Idata1); Vector IV2(3, Idata2), IVa(3), IV
38、b(3); Vector IV2(3, Idata2), IVa(3), IVb(3);intIdot;intIdot;doubleDdot;doubleDdot;coutn-endl;coutn-endl;coutcout測試測試Vector:endl;Vector:endl;coutDV1coutDV1的值是的值是:endl;:endl;42範例程式檔案範例程式檔案TestVector.cpp(4/6)DV1.Display();DV1.Display();coutDV2coutDV2的值是的值是:endl;:endl; DV2.Display(); DV2.Display(); DVa=
39、DV1+DV2; DVa=DV1+DV2;cout(DV1+DV2)cout(DV1+DV2)的值是的值是:endl;endl; DVa.Display(); DVa.Display();DVb=DV1/2.0;DVb=DV1/2.0;cout(DV1/2.0)cout(DV1/2.0)的值是的值是:endl;:endl;43範例程式檔案範例程式檔案TestVector.cpp(5/6)coutcoutDVb1DVb1DVb2DVb2DVb3DVb3endl;endl;Ddot = DV1*DV2;Ddot = DV1*DV2;coutDV1coutDV1和和DV2DV2的內積是的內積是:Dd
40、otendl;Ddotendl;coutn-coutn-endl;endl;coutcout測試測試Vector:Vector: endl;endl;coutIV1coutIV1的值是的值是:endl;endl;44範例程式檔案範例程式檔案TestVector.cpp(6/6)IV1.Display();IV1.Display();coutIV2coutIV2的值是的值是:endl;endl; IV2.Display(); IV2.Display(); IVa=IV1+IV2; IVa=IV1+IV2;cout(IV1+IV2)cout(IV1+IV2)的值是的值是:endl;endl; IV
41、a.Display(); IVa.Display(); IVb=IV1/2.0; IVb=IV1/2.0;cout(IV1/2.0)cout(IV1/2.0)的值是的值是:endl;endl; IVb.Display(); IVb.Display(); Idot = IV1*IV2; Idot = IV1*IV2;coutIV1coutIV1和和IV2IV2的內積是的內積是:IdotIdotendl;endl;return0;return0;45程式執行結果程式執行結果(1/2) -測試測試Vector:Vector:DV1DV1的值是的值是:2.00000.50004.60002.00000
42、.50004.6000DV2DV2的值是的值是:4.00006.50003.80004.00006.50003.8000(DV1+DV2)(DV1+DV2)的值是的值是: :6.00007.00008.40006.00007.00008.4000(DV1/2.0)(DV1/2.0)的值是的值是:1.00000.25002.30001.00000.25002.3000DV1DV1和和DV2DV2的內積是的內積是:28.7300:28.7300- 46程式執行結果程式執行結果(2/2)測試測試Vector:Vector:IV1IV1的值是的值是: :256256IV2IV2的值是的值是:46538
43、46538(IV1+IV2)(IV1+IV2)的值是的值是: :6704467044(IV1/2.0)(IV1/2.0)的值是的值是: :123123IV1IV1和和IV2IV2的內積是的內積是:561:5614723.3 矩陣矩陣 n n二維陣列稱為二維陣列稱為矩陣矩陣(matrix)(matrix)。 n n向量的向量的外積外積(outerproduct)(outerproduct) 也會產生矩陣。也會產生矩陣。 n n矩陣內的單一行或單一列抽離出來也可形成向矩陣內的單一行或單一列抽離出來也可形成向量。量。 48使用指標定義矩陣使用指標定義矩陣(1/7) n n以動態配置的方式在執期間設定
44、矩陣語法有兩種:以動態配置的方式在執期間設定矩陣語法有兩種:(1)(1)將各列在記憶體中獨立設定將各列在記憶體中獨立設定 intM=3;intM=3;intN=4;intN=4;float*A=newfloat*M;float*A=newfloat*M;for(inti=0;iM;i+)for(inti=0;iM;i+)Ai=newfloatN;Ai=newfloatN;49使用指標定義矩陣使用指標定義矩陣(2/7)n n將各列在記憶體中獨立設定將各列在記憶體中獨立設定 相當於在記憶中動態配置了圖中所示的指標和記憶空間:相當於在記憶中動態配置了圖中所示的指標和記憶空間: 圖23.3.1二維陣列
45、的動態記憶體配置50使用指標定義矩陣使用指標定義矩陣(3/7)n n回收指令為回收指令為 :for(inti=0;iM;i+)for(inti=0;iM;i+)deleteAideleteAideleteA;deleteA;51使用指標定義矩陣使用指標定義矩陣(4/7)(2)(2)將各列在記憶體中連續配置將各列在記憶體中連續配置 (3)(3) intM=3;intM=3;(4)(4)intN=4;intN=4;(5)(5)float*A=newfloat*M;float*A=newfloat*M;(6)(6)A0=newfloatM*N;A0=newfloatM*N;(7)(7)for(int
46、i=1;iM;i+)for(inti=1;iM;i+)(8)(8)Ai=Ai-1+N;Ai=Ai-1+N;52使用指標定義矩陣使用指標定義矩陣(5/7)n n將各列在記憶體中連續配置將各列在記憶體中連續配置A A也是指標陣列的指標,但指標陣列的元素也是指標陣列的指標,但指標陣列的元素A0A0,A1 A1 和和A2 A2 各指向同一個一維陣列的不同位址各指向同一個一維陣列的不同位址 圖23.3.2二維陣列A的儲存方式及相關的指標53使用指標定義矩陣使用指標定義矩陣(6/7)n n這種配置方式的回收指令為:這種配置方式的回收指令為:deleteA0deleteA0deleteA;deleteA;n
47、 n將索引的預設表示法修正為慣用的表示法將索引的預設表示法修正為慣用的表示法intM=3;intM=3;intN=4;intN=4;Float*A=newfloat*M+1;Float*A=newfloat*M+1;A0=newfloatM*N+1;A0=newfloatM*N+1;A1=A0;A1=A0;for(inti=2;i=M;i+)for(inti=2;i=M;i+)Ai=Ai-1+N;Ai=Ai-1+N;54使用指標定義矩陣使用指標定義矩陣(7/7)n n將索引的預設表示法修正為慣用的表示法將索引的預設表示法修正為慣用的表示法圖23.3.3符合習慣的二維陣列A的連讀儲存方式及相關的
48、指標5523.4 Matrix樣版類別樣版類別 n nMatrixMatrix樣版類別的建構函數樣版類別的建構函數n n 為了使用上的方便,根本上所有向量和矩陣的為了使用上的方便,根本上所有向量和矩陣的初始值都是以一維陣列的形式給予。初始值都是以一維陣列的形式給予。 例如:例如: n n double W1=2.1, 0.5, 3.2, 6.4, 8.2, 4.9; double W1=2.1, 0.5, 3.2, 6.4, 8.2, 4.9;n n Matrix M1(2,3, W1); Matrix M1(2,3, W1); 56定義定義Matrix樣版類別的建構函數樣版類別的建構函數 t
49、emplatetemplateMatrix:Matrix(intRow,intCol,constT*V)Matrix:Matrix(intRow,intCol,constT*V)Create(Row,Col);Create(Row,Col);for(inti=1;i=M;i+)for(inti=1;i=M;i+)for(intj=1;j=N;j+)for(intj=1;j=N;j+)Aij=V(i-1)*Col+(j-1);Aij=V(i-1)*Col+(j-1);return;return; 57配置矩陣空間的成員函數配置矩陣空間的成員函數Create()n n這個成員函數在處理前先進行參數
50、檢查的動作:這個成員函數在處理前先進行參數檢查的動作:emplateemplatevoidMatrix:Create(intRow,intCol)voidMatrix:Create(intRow,intCol) Check(Row1)|(Col1),Check(Row1)|(Col1),矩陣建構錯誤矩陣建構錯誤,行列大小不能為負值行列大小不能為負值!);!);M=Row;M=Row;N=Col;N=Col;A=newT*M+1;A=newT*M+1;A0=newTM*N+1;A0=newTM*N+1;A1=A0;A1=A0;for(inti=2;i=M;i+)for(inti=2;i=M;i+
51、)Ai=Ai-1+N;Ai=Ai-1+N; 58重載運算子重載運算子 n n方便使用索引方便使用索引(index)(index)來存取矩陣元素。例如:來存取矩陣元素。例如:M32=4.8;M32=4.8;floatx=M46;floatx=M46;n n雖然矩陣元素有兩個下標,我們並不需要重新定雖然矩陣元素有兩個下標,我們並不需要重新定義兩重索引運算子。因為每一個一維陣列的元素義兩重索引運算子。因為每一個一維陣列的元素都可以經由預設的索引運算子得到。都可以經由預設的索引運算子得到。59重載第一重索引運算子重載第一重索引運算子operator () n n T*operator(inti)ret
52、urnAi;T*operator(inti)returnAi; 它的返回資料型態是指標它的返回資料型態是指標T*T*。60矩陣和向量之間互相轉換的成員函數矩陣和向量之間互相轉換的成員函數 n n我們將我們將13.513.5節的函數節的函數PickRow()PickRow()和和SetCol()SetCol()修改修改成樣版類別的成員函數成樣版類別的成員函數SetCol()SetCol()和和PickCol()PickCol()。n n成員函數成員函數SetCol()SetCol()用來將某個向量所有元素的值用來將某個向量所有元素的值複製到矩陣裏面某一個選定的行裏面。複製到矩陣裏面某一個選定的行
53、裏面。n n成員函數成員函數PickCol()PickCol()將矩陣的某一行所有元素的值將矩陣的某一行所有元素的值複製出來成為一個新的向量。複製出來成為一個新的向量。61定義成員函數定義成員函數 PickCol() templatetemplateVectorMatrix:PickCol(intI)VectorMatrix:PickCol(intI)VectorTempV(M);VectorTempV(M);for(inti=1;i=M;i+)for(inti=1;i=M;i+)TempVi=AiI;TempVi=AiI;returnTempV;returnTempV; 62定義成員函數定義
54、成員函數 SetCol() templatetemplate voidMatrix:SetCol(intj,Vector&voidMatrix:SetCol(intj,Vector&V1)V1)for(inti=1;i=M;i+)for(inti=1;i=M;i+)Aij=V1i;Aij=V1i;return;return; 63範例程式檔案範例程式檔案 Matrix.h (樣版類別樣版類別Matrix的完整定義的完整定義)(1/16) /Matrix.h/Matrix.h#ifndefMatrix_H#ifndefMatrix_H#defineMatrix_H#defineMatrix_H#
55、include#include#include#includeusingnamespacestd;usingnamespacestd;64範例程式檔案範例程式檔案 Matrix.h (樣版類別樣版類別Matrix的完整定義的完整定義)(2/16)/=/=宣告宣告MatrixMatrix樣版類別樣版類別=templatetemplateclassMatrixclassMatrixprivate:private:intM,N;intM,N;T*A;T*A;voidCreate(int,int);voidCreate(int,int);public:public:/宣告建構函數宣告建構函數Matri
56、x(int,int);Matrix(int,int);Matrix(int,int,constT*);Matrix(int,int,constT*);65範例程式檔案範例程式檔案 Matrix.h (樣版類別樣版類別Matrix的完整定義的完整定義)(3/16)/宣告複製建構函數宣告複製建構函數Matrix(Matrix&);Matrix(Matrix&);/宣告解構函數宣告解構函數Matrix();Matrix();/operator/operator/宣告指派運算子宣告指派運算子operator=()operator=()Matrixoperator=(constMatrix&);Matr
57、ixoperator=(constMatrix&);/宣告加法運算子宣告加法運算子operator+()operator+()Matrixoperator+(constMatrix&)Matrixoperator+(constMatrix&); ; 66範例程式檔案範例程式檔案 Matrix.h (樣版類別樣版類別Matrix的完整定義的完整定義)(4/16)/宣告乘法運算子宣告乘法運算子operator*()operator*()Matrixoperator*(constMatrix&);Matrixoperator*(constMatrix&);/宣告索引運算子宣告索引運算子operato
58、r()operator()T*operator(inti)returnAi;T*operator(inti)returnAi;/宣告成員函數宣告成員函數SetCol()SetCol()voidSetCol(int,Vector&);voidSetCol(int,Vector&);/宣告成員函數宣告成員函數PickCol()PickCol()VectorPickCol(int);VectorPickCol(int);/宣告成員函數宣告成員函數Display()Display()voidDisplay();voidDisplay();67範例程式檔案範例程式檔案 Matrix.h (樣版類別樣版類
59、別Matrix的完整定義的完整定義)(5/16)/=/=成員函數的定義成員函數的定義=/函數函數Create()Create()的定義的定義templatetemplatevoidMatrix:Create(intRow,intCol)voidMatrix:Create(intRow,intCol) Check(Row1)|(Col1),Check(Row1)|(Col1),矩陣建構錯誤矩陣建構錯誤,行列大小不能為負值行列大小不能為負值!);!);M=Row;M=Row;N=Col;N=Col;A=newT*M+1;A=newT*M+1;A0=newTM*N+1;A0=newTM*N+1;68
60、範例程式檔案範例程式檔案 Matrix.h (樣版類別樣版類別Matrix的完整定義的完整定義)(6/16)A1=A0;A1=A0;for(inti=2;i=M;i+)for(inti=2;i=M;i+)Ai=Ai-1+N;Ai=Ai-1+N; /建構函數的定義建構函數的定義templatetemplateMatrix:Matrix(intRow,intCol)Matrix:Matrix(intRow,intCol)Create(Row,Col);return;Create(Row,Col);return;69範例程式檔案範例程式檔案 Matrix.h (樣版類別樣版類別Matrix的完整定義
61、的完整定義)(7/16)/建構函數的定義建構函數的定義(從一維陣列建立二維陣列從一維陣列建立二維陣列) )templatetemplateMatrix:Matrix(intRow,intCol,constMatrix:Matrix(intRow,intCol,constT*V)T*V)Create(Row,Col);Create(Row,Col);for(inti=1;i=M;i+)for(inti=1;i=M;i+)for(intj=1;j=N;j+)for(intj=1;j=N;j+)Aij=V(i-1)*Col+(j-1);Aij=V(i-1)*Col+(j-1);return;retu
62、rn;70範例程式檔案範例程式檔案 Matrix.h (樣版類別樣版類別Matrix的完整定義的完整定義)(8/16)/複製建構函數的定義複製建構函數的定義templatetemplateMatrix:Matrix(Matrix&OldM)Matrix:Matrix(Matrix&OldM)Create(OldM.M,OldM.N);Create(OldM.M,OldM.N);for(inti=1;i=M;i+)for(inti=1;i=M;i+)for(intj=1;j=N;j+)for(intj=1;j=N;j+)Aij=OldM.Aij;Aij=OldM.Aij;return;retur
63、n;71範例程式檔案範例程式檔案 Matrix.h (樣版類別樣版類別Matrix的完整定義的完整定義)(9/16)/解構函數的定義解構函數的定義templatetemplateMatrix:Matrix()Matrix:Matrix()deleteA0;deleteA0;deleteA;deleteA;72範例程式檔案範例程式檔案 Matrix.h (樣版類別樣版類別Matrix的完整定義的完整定義)(10/16)/定義指派運算子定義指派運算子operator=()operator=()templatetemplateMatrixMatrixMatrix:operator=(constMat
64、rix&M2)Matrix:operator=(constMatrix&M2)if(M!=M2.M)|(N!=M2.N)if(M!=M2.M)|(N!=M2.N)Create(M2.M,M2.N);Create(M2.M,M2.N);for(inti=1;i=M;i+)for(inti=1;i=M;i+)for(intj=1;j=N;j+)for(intj=1;j=N;j+)Aij=M2.Aij;Aij=M2.Aij;return*this;return*this; 73範例程式檔案範例程式檔案 Matrix.h (樣版類別樣版類別Matrix的完整定義的完整定義)(11/16)/定義加法運算
65、子定義加法運算子operator+()operator+()templatetemplateMatrixMatrixMatrix:operator+(constMatrix&M2)Matrix:operator+(constMatrix&M2)Check(M!=M2.M)|(N!=M2.N),Check(M!=M2.M)|(N!=M2.N),矩陣加法運算錯誤矩陣加法運算錯誤,大小不相同大小不相同!);!);Matrixtemp(M,N);Matrixtemp(M,N);for(inti=1;i=M;i+)for(inti=1;i=M;i+)for(intj=1;j=N;j+)for(intj=
66、1;j=N;j+)temp.Aij=Aij+M2.Aij;temp.Aij=Aij+M2.Aij;returntemp;returntemp; 74範例程式檔案範例程式檔案 Matrix.h (樣版類別樣版類別Matrix的完整定義的完整定義)(12/16)/定義乘法運算子定義乘法運算子operator*()operator*()templatetemplateMatrixMatrixMatrix:operator*(constMatrix&M2)Matrix:operator*(constMatrix&M2)Check(N!=M2.M,Check(N!=M2.M,矩陣乘法運算錯誤矩陣乘法運算
67、錯誤,大小不配大小不配!);!);Matrixtemp(M,M2.N);Matrixtemp(M,M2.N);for(inti=1;i=M;i+)for(inti=1;i=M;i+)for(intj=1;j=M2.N;j+)for(intj=1;j=M2.N;j+)75範例程式檔案範例程式檔案 Matrix.h (樣版類別樣版類別Matrix的完整定義的完整定義)(13/16) temp.Aij=0.0;temp.Aij=0.0;for(intk=1;k=N;k+)for(intk=1;k=N;k+)temp.Aij+=Aik*M2.Akj;temp.Aij+=Aik*M2.Akj;retur
68、ntemp;returntemp;/定義成員函數定義成員函數Display()Display()templatetemplatevoidMatrix:Display()voidMatrix:Display()76範例程式檔案範例程式檔案 Matrix.h (樣版類別樣版類別Matrix的完整定義的完整定義)(14/16)coutsetiosflags(ios:right)coutsetiosflags(ios:right)setiosflags(ios:fixed)setiosflags(ios:fixed)setiosflags(ios:showpoint)setiosflags(ios:s
69、howpoint)setprecision(4);setprecision(4);for(inti=1;i=M;i+)for(inti=1;i=M;i+)for(intj=1;j=N;j+)for(intj=1;j=N;j+)coutsetw(10)coutsetw(10)Aij;Aij;coutendl;coutendl;return;return; 77範例程式檔案範例程式檔案 Matrix.h (樣版類別樣版類別Matrix的完整定義的完整定義)(15/16)/定義成員函數定義成員函數PickCol()PickCol()templatetemplateVectorMatrix:PickC
70、ol(intI)VectorMatrix:PickCol(intI)VectorTempV(M);VectorTempV(M);for(inti=1;i=M;i+)for(inti=1;i=M;i+)TempVi=AiI;TempVi=AiI;returnTempV;returnTempV;78範例程式檔案範例程式檔案 Matrix.h (樣版類別樣版類別Matrix的完整定義的完整定義)(16/16)/定義成員函數定義成員函數SetCol()SetCol()templatetemplatevoidMatrix:SetCol(intj,Vector&voidMatrix:SetCol(intj
71、,Vector&V1)V1)for(inti=1;i=M;i+)for(inti=1;i=M;i+)Aij=V1i;Aij=V1i;return;return; #endif#endif79範例程式檔案範例程式檔案TestVM.cpp (1/5)n n我們分別驗證了兩個矩陣間的加法和乘法的正確我們分別驗證了兩個矩陣間的加法和乘法的正確性。此外,由於要使用性。此外,由於要使用SetCol()SetCol()和和PickCol()PickCol()這兩個成員函數,這個程式必需在這兩個成員函數,這個程式必需在開頭處以開頭處以 #includeVector.h#includeVector.h#incl
72、udeMatrix.h#includeMatrix.hn n我們可以由這個簡單的範例發現,使用自訂的樣我們可以由這個簡單的範例發現,使用自訂的樣版類別版類別VectorVector和和MatrixMatrix可以大大地簡化主程式的撰可以大大地簡化主程式的撰寫。而且樣版類別一旦建構完成,可以應用到各寫。而且樣版類別一旦建構完成,可以應用到各式各樣的問題,非常方便。式各樣的問題,非常方便。80範例程式檔案範例程式檔案TestVM.cpp (2/5)/TestVM.cpp/TestVM.cpp#includeVector.h#includeVector.h#includeMatrix.h#inclu
73、deMatrix.h#include#include#include#includeusingnamespacestd;usingnamespacestd;81範例程式檔案範例程式檔案TestVM.cpp (3/5)intmain()intmain() doubleW1=2.1,0.5,3.2,6.4,8.2,4.9;doubleW1=2.1,0.5,3.2,6.4,8.2,4.9;doubleW2=4.6,6.5,3.6,4.2,5.8,9.4;doubleW2=4.6,6.5,3.6,4.2,5.8,9.4;doubleW3=2.1,3.2,9.8,6.9,2.4,1.6;doubleW3
74、=2.1,3.2,9.8,6.9,2.4,1.6;doublew1=2,0.5;doublew1=2,0.5;doublew2=4,6.5;doublew2=4,6.5;Matrix M1(2,3, W1);Matrix M1(2,3, W1);Matrix M2(2,3, W2);Matrix M2(2,3, W2); Matrix M3(3,2, W3); Matrix M3(3,2, W3); Matrix Ma(2,3), Mb(2,2); Matrix Ma(2,3), Mb(2,2); Vector V1(2, w1); Vector V1(2, w1); Vector V2(2,
75、 w2), Xa(3), Xb(3); Vector V2(2, w2), Xa(3), Xb(3); 82範例程式檔案範例程式檔案TestVM.cpp (4/5)coutM1coutM1是是:endl;:endl; M1.Display(); M1.Display();coutM2coutM2是是:endl;:endl; M2.Display(); M2.Display();coutM3coutM3是是:endl;:endl; M3.Display(); M3.Display(); Ma=M1+M2; Ma=M1+M2;cout(M1+M2)cout(M1+M2)是是:endl;:endl;
76、 Ma.Display(); Ma.Display(); Mb=M1*M3; Mb=M1*M3;83範例程式檔案範例程式檔案TestVM.cpp (5/5)cout(M1*M3)cout(M1*M3)是是:endl;:endl; Mb.Display(); Mb.Display(); V2 = M1.PickCol(2); V2 = M1.PickCol(2);coutM1coutM1的第的第2 2行是行是:endl;:endl; V2.Display(); V2.Display();coutV1coutV1是是:endl;:endl; V1.Display(); V1.Display();M
77、1.SetCol(3,V1);M1.SetCol(3,V1);coutcout將將M1M1的第的第3 3行設為行設為V1V1後後nnM1M1變成為變成為:endl;:endl; M1.Display(); M1.Display();return0;return0; 84程式執行結果程式執行結果(1/2) M1M1是是:2.10000.50003.20002.10000.50003.20006.40008.20004.90006.40008.20004.9000M2M2是是:4.60006.50003.60004.60006.50003.60004.20005.80009.40004.20005
78、.80009.4000M3M3是是:2.10003.20002.10003.20009.80006.90009.80006.90002.40001.60002.40001.6000(M1+M2)(M1+M2)是是:6.70007.00006.80006.70007.00006.800010.600014.000014.300010.600014.000014.300085程式執行結果程式執行結果(2/2)(M1*M3)(M1*M3)是是:16.990015.290016.990015.2900105.560084.9000105.560084.9000M1M1的第的第2 2行是行是:0.500
79、08.20000.50008.2000V1V1是是:2.00000.50002.00000.5000 將將M1M1的第的第3 3行設為行設為V1V1後後M1M1變成為變成為:2.10000.50002.00002.10000.50002.00006.40008.20000.50006.40008.20000.50008623.5 物件陣列的動態創造和刪除物件陣列的動態創造和刪除 對於一維陣列而言,對於一維陣列而言,int*pV=newint200;int*pV=newint200;能夠在記憶堆上配置出能夠裝得下能夠在記憶堆上配置出能夠裝得下200200個個intint資料的空間。資料的空間。
80、回收這個記憶空間的指令:回收這個記憶空間的指令:deletepV;deletepV; 這就是包裝在樣版類別這就是包裝在樣版類別VectorVector的成員函數的成員函數Create()Create()和解和解構函數構函數Vector()Vector()內的主耍內容。內的主耍內容。87物件陣列的動態創造和刪除物件陣列的動態創造和刪除 如果自訂的類別名稱是如果自訂的類別名稱是MyClassMyClass,則動態產生和回收,則動態產生和回收200200個物件的語法和根本資料型態的語法一致的。例如個物件的語法和根本資料型態的語法一致的。例如 MyClass*pA=newMyClass200;MyCl
81、ass*pA=newMyClass200; 至於回收記憶空間的語法也和根本資料型態相同至於回收記憶空間的語法也和根本資料型態相同( (注意,注意,這個時候中括號這個時候中括號不可以省略不可以省略) ): deletepA;deletepA;88範例程式檔案範例程式檔案 VectorCD.h(1/6) n n改寫改寫23.223.2節樣版類別節樣版類別VectorVector的定義,成為標頭檔的定義,成為標頭檔VectorCD.hVectorCD.h,讓每一次建構函數和解構函數被,讓每一次建構函數和解構函數被呼叫時都會對外顯示訊息,並加上兩個呼叫時都會對外顯示訊息,並加上兩個staticstat
82、ic資料資料成員:成員:CountConstCountConst和和CountDistCountDist,以分別計,以分別計算建構函數和解構函數被呼叫的次數。至於其它算建構函數和解構函數被呼叫的次數。至於其它的運算子重載部份則暫時移除,讓程式更加精簡。的運算子重載部份則暫時移除,讓程式更加精簡。 89範例程式檔案範例程式檔案 VectorCD.h(2/6)/VectorCD.h/VectorCD.h#ifndefVectorCD_H#ifndefVectorCD_H#defineVectorCD_H#defineVectorCD_H#include#include#include#includ
83、eusingnamespacestd;-usingnamespacestd;-template/template/宣告宣告VectorVector樣版類別樣版類別90範例程式檔案範例程式檔案 VectorCD.h(3/6)classVectorclassVector private:private:intSize;intSize;T*V;T*V; static int CountConst, CountDist; static int CountConst, CountDist;inlinevoidCreate(int);inlinevoidCreate(int);public:public:
84、/宣告建構函數宣告建構函數Vector():Size(1)Create(1);Vector():Size(1)Create(1);Vector(intN):Size(N)Create(N);Vector(intN):Size(N)Create(N);Vector(int,constT*);Vector(int,constT*);/宣告解構函數宣告解構函數Vector();Vector();91範例程式檔案範例程式檔案 VectorCD.h(4/6)/-/-將將staticstatic資料成員初始化資料成員初始化-template template int Vector:CountConst =
85、 0;int Vector:CountConst = 0;template template int Vector:CountDist = 0;int Vector:CountDist = 0;/-/-定義定義VectorVector樣版類別樣版類別-/成員函數成員函數Create()Create()的定義的定義templatetemplatevoidVector:Create(intN)voidVector:Create(intN)if(N0)if(N0)92範例程式檔案範例程式檔案 VectorCD.h(5/6) Size=0;V=0;Size=0;V=0;cerrcerr呼叫建構函數發生
86、錯誤呼叫建構函數發生錯誤,向量長度不能為負向量長度不能為負值值!n;!n;elseelse Size = N; V = new TN+1; Size = N; V = new TN+1; CountConst+; CountConst+; cout cout 第第第第 CountConst CountConst 次呼叫建構次呼叫建構次呼叫建構次呼叫建構函數函數函數函數n;n; 93範例程式檔案範例程式檔案 VectorCD.h(6/6)/解構函數的定義解構函數的定義templatetemplateVector:Vector()Vector:Vector() delete V; delete V
87、;CountDist+;CountDist+; cout cout 第第第第 CountDist CountDist 次次次次呼叫解構函數呼叫解構函數呼叫解構函數呼叫解構函數 endl; endl; #endif#endif94範例程式檔案範例程式檔案 TestVectorCD.cpp (1/2) 分別使用分別使用VectorVector動態宣告動態宣告5 5個個VectorVector物件,以驗物件,以驗證建構函數和解構函數被呼叫的情況證建構函數和解構函數被呼叫的情況。/TestVectorCD.cpp/TestVectorCD.cpp#includeVectorCD.h#includeVe
88、ctorCD.hintmain()intmain() cout(1)cout(1)執行執行Vector*pV=newVector5;Vector*pV=newVector5;:n;:n;Vector*pV=newVector5;Vector*pV=newVector5; 95範例程式檔案範例程式檔案 TestVectorCD.cpp (2/2)coutendl;coutendl;cout(2)cout(2)執行執行 deletepV;deletepV;:endl;endl;deletepV;deletepV;int*pI=newint8;int*pI=newint8;deletepI;retu
89、rn0;deletepI;return0;96程式執行結果程式執行結果 (1) (1) 執行執行 Vector* pV = new Vector5;Vector* pV = new Vector5;: : 第第 1 1 次呼叫建構函數次呼叫建構函數 第第 2 2 次呼叫建構函數次呼叫建構函數 第第 3 3 次呼叫建構函數次呼叫建構函數 第第 4 4 次呼叫建構函數次呼叫建構函數 第第 5 5 次呼叫建構函數次呼叫建構函數(2) (2) 執行執行 delete pV;delete pV;: : 第第 1 1 次呼叫解構函數次呼叫解構函數 第第 2 2 次呼叫解構函數次呼叫解構函數 第第 3 3
90、次呼叫解構函數次呼叫解構函數 第第 4 4 次呼叫解構函數次呼叫解構函數 第第 5 5 次呼叫解構函數次呼叫解構函數 97FPTIaj!cJcO6i6zpG5Qu5FYQc3jQn(z!-O(IGU5rHIoKxMbZIr1vCep#KGHFs-f0hYLJKGq!2OVg#Is6GVH&KM!dzNMoGmuVp+F3jbHATj*ZePyHdpdUiOg*mcJUQFtpA)Xed$u#7ANC(X4Ef&G7qkQJ#n*Eq-Z8#de+Mp97q2f+)Mxg!nv8jWHEGF5yftbDOPNQ&sf%1x8$Ot&aBcvsbXAllH8#+s-IhQ)Iag*tQ0nK$Vg
91、6kPjLbZWc0v!)antkZyXUy)sI3h8ExThEW8Fb7GATjH*o&T0QvwN28ZV2MK$vc+O1DtN(Aoo75eEk0l*WLGGSiwcnN+dpYsLCGWRxpP)+TxMBr+NbKptDBY6qH!8upMSBs-Hq0*ht1*vf+GA8cztt(FnZHShl+uSDkJkmMKD0nXy*qDg-3bT5rzeUF#xir&Ln9qn*NJ&+&$DU9NST!*M3Ku#oZP$7)jl#tCJfV)3La+kVn5P9LLjiFeBOBa0v)EjOpy!+rJ5RTGa5!Df1jnSa-ZmvuC&lEUBcCn9C*dFIrtF
92、XV4#zlSjDP%1Aa)NSI5zfwm-E+cdiz5nSwv%PLOvRDX5dqu$&%G6i2WlP8f5-5Mi*R)9(FkiP6fr%$-3YKzEf+Yplqtob5Qtm9rtjsHCe+$*AEY4QG-75*JeqNwg5JuQMo0kGqJukeRSk$MVOJeG+Z!HO0dg3(CxXG6a-AfJ*!*5s5osB$p69W7%n%yA(kEQ#waZT0#8GWOWtE3NMg!WyiP2Dn8hE)5QXX4*iUB9bWes4hRA13qlT$YMn4B!P5NWobH5UdW8nP!rjej9d1u4IOUu7LVNf8&WzfH#zLekO14B
93、II0ybVYiP53EFF+E+PY!(o%9ClNLLOO%n8anZH-5iHigPIJfOdT*YonO6iovMqGqIg79hemLrDjYNMNJt%2MQ8O3oPlcwgIOHuieqZTfj5Pk!JJ)R55WtyZ51HOh7cqGUYd*c0C#o6Qbk-nT*&YMGjJCG!$TH)*J-KnNKKMI7IBDF%vtTgEGfbLFCG!+myrQ+IXzyRb8-kaj60p-jzbLrk1Tc&rR0-P1c-vue(1aKqHfrn)kuMm!7OU+Oq9C#kv-dL*Ktk4(Si-aJbj5ZUKJroI0DM6p3iSPn%&vdfaQ)TZc
94、)R)cYU(S6k6DUP)xA8yO75CtB2%u(Tvhe1reGh5v0G*&Frg5SkICxUo(n$fFE3bhOY%3sT3G6Cd6j*+I4z+B&WGHZ)fF&0WDkDZvzHS57I01L41YOpirWCceAbkz6!MTB8tbU1BR38)2uh!m!t-VYBRt2Vu0L0%ux&OSLDCPd445r!x3zRLa8w4XMx9DIhmQsf4ZyYXplF4MlZlgDqU%XK-2$uDaq7MbT8f+nrgYkTmOL$FIN+uIhtn#G9q49klCrwAEoB+2O#KAN(rAZfMIS7DqB5Xmz&gw6wcxR%!NIn0P
95、zq*Hf4%VI#!uyg2e#UMVWwA8L&80W#mK4Fhy3dJAei&j-oDmX0-feTLADf2PeF(+EaZjX6RJCQ8l2W%t0IIFVuJdFtUKaoz5IWvs2yuut+S0cUDVcyqw!8T!RhkEf3yEQlE4StqyVLLG0-4lkqENU6S!$BpmkjFb9HW3y0B*nv)0M4kuG$vmJ0Aib81Shq2q*jzM*r7fW0!%oT8h5z7VfwHMqY-VI5j9b9C)R)Oh2CFTy&z%D!uuTiJV8A5*ApfjxwAyF2qQ5lgG3WYYk#*qwEZo(zmo3n)l%vx8JEmEM9zv
96、YK!EKzLOuSTWA4xOw$kXUMUJ5#AF!FvtPgGZhoJJ!KL%h!A#ZJMxdizt6ND&WXDKyP*SjxIQ-tpf!8uMw9EDh0lkJlOoR%PoBbF9PcUXFZD#Ii#*3!meZequzYwSK0SU+jAX(tlRWKn(JxD0&t$-duGEjFtZlDNX4(e3r8rd%L&Xs(praOb*MMvKkg0WeBX*021icia99KRnn#rLgX#TgcBrYN17x(9l#iu!NcKZ959X33$&0VZ3l6DSUYcd$H9$6%wVn*rAtXe#R*ZGV+2%k)vy4Aclq0xhRWqaG+)+o+eL
97、yUcU0rHXSn1gMeGwXCWEHFTq3XOvTYI6r&PrYyTF1elprj%e3pwDAutD(Q-UkDOY3wagW-H&pT5c)bm5E!o4L24YVsPCseKhfWXnS48Ti4iAhf)Ye3+eD8D4S-fLij$zvbv)#!6iE2-e4DQ7QQhb5Z30AMV5zzSRVJU-$Hmog+Wrh8UV7k2R48yaXXf2vpibcPFGLuKmyF&A!PdA&*DOtN*JAuy#WGgA8#g3+zG#48NMz+sUfBA7dL3766fEhp+fepDOPy!Yg)(vlfmMtJv&j8)Ql&3M%ZZeBSS6IovNaDx$
98、tFc8mRb&zHxS4PL52IcmnGEEEv5oeKa41fgxUvctJT8l+XiEQMgp&M%os!%lYzPoo1EOc%vLE#Y94F(qkCDeY9DI$FK-BNlH(mtILmC)6he9MX-(!t1Xo5q$dCQZydKSu%vPZ(8v1B77v*Im%oxfx84fxUKP7$faKbSmRDNjrmVwaOf-oS$PmNhSwuNY5eoDSVNf27b-0IkK!Nhe-4O$mFghORtIbtPjufI5zLhV1l1+vNveeq%xREHE)KWB-Qn9%pp*S!GH(JoUXZIBfURkf)-Bs)SMbm(m0$R-yn$5Hs78
99、crZWBLaZNDo(cgT$PnXn&QI75v6&YRAvfucDUX*+G*IN-J+-&BnJxTUfK$n+1YsN9kwUD2E)KedDz-)dqr4bgGtZ56urkD!upV%BPs(hW!y88V&QvQTZ4gmnJMk4b2T2n1A&xXHwgneDe-kUug3NcCnJac1P&0!2&ptfK5wMLk+qte#zd4ePOjBEzstZpx44qZ4A3XD2+oDT*n+u+pdJmpyUvMKpn#oSuyqylq0E1i1DwwdKZcWfR8doB8EwJc%8E5T$QqInHGHy#bx5f6xaH2VP1*8MpbfV!$unEKf&)30a
100、HEj%4#3VEKA6LnmaHD!*7dkz&MY)KGP$33XhjY41ZJyzS3(j%UPPUt#&01RcSnPx*x1Jzohp#s%bAtGZ!KJk58eMB6itS4vB4Iw%6)QXanDi5w(QcD8Kcfd5y38vaLahj88eOBNVe(P(jQ&QuTS*g-MHe4spw&x-8-e#5E(y4F&1R+MTDdXC1YidBb0*#Vd!+IGIX7908$0G)T1tSDItBuD1j)NO3OIG+iouY3OEDNR)l!STm-blwFsIch(j%BgW8)TKimKLNI26zFO2C$+aUaYJefVrgmuWm-j7%MF&1lXS
101、swX0kC#res68apM-dcZ9!15yWdMtxyvSovL*qspZPw(8TaRXEM0uHHmonyi2lHhCId(BrnEh4CUAB4TVh$TDa*egSIJkW7Yp7UPhw+1t0Or5zauLyfumGyFyWBnHQ#qpHrr(WR#ft7fJhAVeWQ4%rFGCzH&GOoXV&6fdHhp16+1uwLmwrn(6U1uuAl8$RP#CEKuuzc5JEbenKUdw7bEQS-ZQ4UC+w914t#P(aUf%NxJOC36W)5r7G#dO+i(yOV9+dZnTeyy6iQ%!SK#MbgVR)pXkGMuRAZy*pWub&g-v9NgI
102、YPb6YJ#SWX#peVP0xz-#wHipp#)gFuPY7wjOtsNpjtqqb3Vkz%9TV+!7jn%vWxQ6ms&WKrNRa!Fvhpmv8iCa+ABI%13GDVhVoMvB01K+bi4WnAhw0MOMP$8m4iR0ngwVu0A4Y3Gp%UTgiX8glo*(UJCH(IPGZ%&KcHWG+w$-TwZ8LJwkQzLcD-d(Y1xW%ITuGdQmpd!3#4KjIf5mzgkF-sRDMefW8fggoMlpDqxR6t$*m8-+iXp*UU4#fc9W+j9mGCGCu5qjCmdPIQ5+Zpl$l&vuAEpCT-ZWWjQdP6nX0YFP
103、ykw0nxh1)KtlLjqsgOHFIX(n2eGh9cikaPyPB+irzOrPK7)8yE7SIM6-gM&o9Pke%10j4zIE2oTZf$N+eQv&b9gGw+XAWgc-7GSGaYxTzFs4z)70cqrxJYZL!8iDxu2N(lKWFI(0K!8g9RG(*LfNf#S+M%Ut$oI(-O*!$MnzU!Wr+n)NSJxt7h#7rHG9jnOL4o(#fYWQn2+G0fCRT)!P4K1rc9Rt+5lj&Ggu45lxus#tDesavjdZ7H2lbCsX*Y#7hdY6Y+v5N)q)$i8XHDE)9Cc+iJTOSS&7mwkLrk2W6LFz
104、VFfKtq1h#xTgEN333ysb!jpzX)(wZMuXtkHsI+JKQu1!dbp(vPktFS3&4U-Cpnq6gJqFnPDBBxhQ#+%B%i+Jtizg!LAct-5(7SR+3CtRJFGJRqHnJB0T&$EO71PMGy%hJL!AlEfr2de4O*tDzHkqmK26%B6eRXPxe+BjJAVtf94!AYSb)4nWxhi#7W!jTeT9gwm6l*0CAfiGuJ(X#qigGaE5*cDKeMQt&4JVKWWfB9Jgq9jk3HKFRgAXM0t7lQ$Tv0&hpb$1SfzO*l$Xd6K&4ajE7+6cGhyM*4ohY1F&8Lam
105、n#CJ0ioxRg1e31H!Aw%&YV)!u3yuhTCJQnV%o0-OyO1wXEcmfIvPSs&rJ09&drgXkOnOWDXCEXeHFvG9bUogecwUv(rmf(Yabe#3VL%bSc4swiXO(g#BSk9+aw0yHEB*4jtQc$J%XDOXhWtx3IwWWLhUqFgbxh$#3oL!%K-W3Gm9*J8j0jMWTUYU1MT3SUM&1D!PACpef6ObmLHKhPkU$NjhGi1FS-+9I2!7n9e6YLDOj(VT)nByyFqD6I4bfNMiDLWTHezoM9c4!RR0YUc%Hzod7RyM+Cf8+O7L&ASJoAH8nGcB6)7PrH7xy6LlLBmLGS7DtvC3#7tZPdzA497G96&Y1sIe%Z9Z7+J7C1KCUyRT5B-q%-u7Gr7+GH4D1JZ!pFtXxZlkwAK57Ny(0uSiCYkO-Ld(urLgINY8519-BHUjE2N-AM$6mz0-zY&bvLPB(%m2BvpoAyJlqSdAId(%dmN$BE&t57gFfec0F(e*uRrfjbksGRr2MrsUqO#DRmbi9xviXMaxq7Q0b3ZTgof(Y5a*qmNqfdaew-C7498