c++ 資料結構 稀疏矩陣類的定義及其各種操作的實現
阿新 • • 發佈:2019-01-25
稀疏矩陣類:
該型別的矩陣中0元素佔多半,我們平常儲存一般矩陣一般用二維陣列,但是該矩陣的0元素既佔用儲存空間,而且在運算中會花費大量時間來進行0元素的無效運算。
因此我們利用三元陣列(注意不是三維陣列)儲存非零元素的座標和值。
以下是稀疏矩陣的類定義和各種操作的實現程式碼:
1.自定義資料型別:包含下標和值,及賦值運算子
# include<iostream> using namespace std; struct Trituple{ //自定義資料結構:矩陣元素的行,列,值; int row,col; int value; Trituple& operator=(Trituple& x){ //賦值運算子過載 row=x.row; col=x.col; value=x.value; return *this; } };
2.稀疏矩陣類:
# include"Trituple.h" # include<iostream> # include<assert.h> using namespace std; const int DefaultSize=100; class SparseMatrix{ //稀疏矩陣 private: int Rows,Cols,Terms; //行數,列數,非零元素的個數 Trituple *smArray; //存非零元素的三元陣列 int maxTerms; //三元組最大可容納的元素個數 public: SparseMatrix(int maxSz=DefaultSize); //建構函式 SparseMatrix(SparseMatrix& SM); //賦值建構函式 ~SparseMatrix(); //解構函式 SparseMatrix& operator=(SparseMatrix& SM); //賦值運算子過載 SparseMatrix Transpose(); //矩陣轉置 SparseMatrix Add(SparseMatrix& b); //矩陣的加法 SparseMatrix Multiply(SparseMatrix& b); //矩陣的乘法 friend ostream& operator<<(ostream& ostr,SparseMatrix& SM); //矩陣的輸出過載函式 friend istream& operator>>(istream& istr,SparseMatrix& SM); //矩陣的輸入過載函式 }; SparseMatrix::SparseMatrix(int maxSz):maxTerms(maxSz){ //建構函式:構造一個大小為maxTerm的三元組,行列數和非零元素個數都置零 if(maxSz<1){ cerr<<"矩陣初始化錯誤!"<<endl; exit(1); } smArray=new Trituple[maxSz]; assert(smArray!=NULL); Rows=Cols=Terms=0; } SparseMatrix::SparseMatrix(SparseMatrix& SM){ //複製建構函式 Rows=SM.Rows; //賦值矩陣的性質 Cols=SM.Cols; Terms=SM.Terms; maxTerms=SM.maxTerms; smArray=new Trituple[maxTerms]; //構造三元組並賦與SM相同的值 assert(smArray!=NULL); for(int i=0;i<Terms;i++) smArray[i]=SM.smArray[i]; } SparseMatrix::~SparseMatrix(){ //解構函式:釋放所有儲存 delete[]smArray; } SparseMatrix& SparseMatrix::operator=(SparseMatrix& SM){ //賦值運算子過載 Rows=SM.Rows; //元素性質的賦值 Cols=SM.Cols; Terms=SM.Terms; maxTerms=SM.maxTerms; for(int i=0;i<Terms;i++) //三元組所有元素賦值 smArray[i]=SM.smArray[i]; return *this; //返回的是對呼叫該函式的物件的引用,需顯式使用this指標; } ostream& operator<<(ostream& ostr,SparseMatrix& SM){ //輸出運算子過載 (為啥代模板就不能呼叫row? ) ostr<<"# Rows="<<SM.Rows<<endl; //輸出該矩陣的性質 ostr<<"# Cols="<<SM.Cols<<endl; ostr<<"# Terms="<<SM.Terms<<endl; for(int i=0;i<SM.Terms;i++) //輸出該矩陣非零元素的位置及值 ostr<<i+1<<": "<<"SM<"<<SM.smArray[i].row<<","<<SM.smArray[i].col<<">="<< SM.smArray[i].value<<endl; return ostr; } istream& operator>> (istream& istr,SparseMatrix& SM){ //輸入運算子過載 cout<<"Please enter number of rows,columns,and terms of Matrix"<<endl; istr>>SM.Rows>>SM.Cols>>SM.Terms; //輸入元素的性質 if(SM.Terms>SM.maxTerms){ cerr<<"Numbers of Terms overflow!"<<endl; exit(1); } for(int i=0;i<SM.Terms;i++){ //依次輸入非零元素的座標和值 cout<<"Enter row,column,and value of term:"<<i+1<<endl; cin>>SM.smArray[i].row>>SM.smArray[i].col>>SM.smArray[i].value; } return istr; } /*SparseMatrix SparseMatrix::Transpose(){ //轉置函式 SparseMatrix b(maxTerms); b.Rows=Rows; b.Cols=Cols; b.Terms=Terms; b.maxTerms=maxTerms; if(Terms>0){ int i,k,CurrentB=0; for(k=0;k<b.Cols;k++) for(i=0;i<Terms;i++) if(smArray[i].col==k){ b.smArray[CurrentB].row=smArray[i].col; b.smArray[CurrentB].col=smArray[i].row; b.smArray[CurrentB].value=smArray[i].value; CurrentB++; } } return b; }*/ SparseMatrix SparseMatrix::Transpose(){ //轉置函式 int *rowSize=new int[Cols]; //轉置矩陣每行非零元素的個數 int *rowStart=new int[Cols]; //轉置矩陣每行第一個非零元素對應其三元組的下標 SparseMatrix b(maxTerms); //轉置後的矩陣對應的三元組 b.Rows=Rows; //b的性質 b.Cols=Cols; b.Terms=Terms; b.maxTerms=maxTerms; if(Terms>0){ int i,j,CurrentB=0; for(i=0;i<Cols;i++) //對rowSize陣列賦值 rowSize[i]=0; for(i=0;i<Terms;i++) rowSize[smArray[i].col]++; rowStart[0]=0; //對rowStart陣列賦值 for(i=1;i<b.Rows;i++) rowStart[i]=rowStart[i-1]+rowSize[i-1]; for(i=0;i<Terms;i++){ //遍歷三元組a,把各個元素按rowStart陣列存在b中相應的位置 j=rowStart[smArray[i].col]; //a陣列中行號按從小到大的順序排列,所以相同列最先遇到的元素肯定處在相應轉置矩陣相應行中的最前面 b.smArray[j].row=smArray[i].col; //把該元素按照找到的下標j存入b中 b.smArray[j].col=smArray[i].row; b.smArray[j].value=smArray[i].value; rowStart[smArray[i].col]++; //因為該值已經存入b,所以轉置矩陣的該行下一個元素在b中對應的下標為rowStart[smArray[i].col]++; } } delete[] rowSize; //釋放new申請的儲存空間 delete[] rowStart; return b; } SparseMatrix SparseMatrix::Add(SparseMatrix& b){ //轉置矩陣的加法 SparseMatrix Result(Rows*Cols); //結果存於Result裡面 if(Rows!=b.Rows||Cols!=b.Cols){ //規格相同的矩陣才能相加 cout<<"Incompatible matrices"<<endl; return Result; } Result.Rows=Rows; Result.Cols=Cols; Result.Terms=0; Result.maxTerms=Rows*Cols; int i=0,j=0,index_a,index_b; //i:遍歷a三元組;index_a:當前所指的a中元素在矩陣中的位置; while(i<Terms&&j<b.Terms){ index_a=smArray[i].row*Cols+smArray[i].col; index_b=b.smArray[j].row*b.Cols+b.smArray[i].col; if(index_a<index_b){ //當前所指的a,b中兩個元素,a中元素位置在前 Result.smArray[Result.Terms].row=smArray[i].row; //直接把a的元素放在Result裡面 Result.smArray[Result.Terms].col=smArray[i].col; Result.smArray[Result.Terms].value=smArray[i].value; i++; //i指標指向a中下一個元素 } if(index_a>index_b){ Result.smArray[Result.Terms].row=b.smArray[j].row; Result.smArray[Result.Terms].col=b.smArray[j].col; Result.smArray[Result.Terms].value=b.smArray[j].value; j++; } if(index_a==index_b){ //位置相同 if(smArray[i].value+b.smArray[j].value){ //如果兩個值相加的和不為零 Result.smArray[Result.Terms].row=smArray[j].row; //把相加的結果放在Result中 Result.smArray[Result.Terms].col=smArray[j].col; Result.smArray[Result.Terms].value=smArray[i].value+b.smArray[j].value; i++; j++; } } Result.Terms++; //存一個元素,非零元素的個數+1; } for(;i<Terms;i++){ //b中元素已經遍歷完,把a剩餘的元素放入Result裡面,此時i所指的第一個元素位置肯定在b中最後一個元素後面 Result.smArray[Result.Terms].row=smArray[i].row; Result.smArray[Result.Terms].col=smArray[i].col; Result.smArray[Result.Terms].value=smArray[i].value; i++; Result.Terms++; } for(;j<b.Terms;j++){ Result.smArray[Result.Terms].row=b.smArray[j].row; Result.smArray[Result.Terms].col=b.smArray[j].col; Result.smArray[Result.Terms].value=b.smArray[j].value; j++; Result.Terms++; } return Result; } SparseMatrix SparseMatrix::Multiply(SparseMatrix& b){ //矩陣的乘法 SparseMatrix Result(Rows*b.Cols); //存放矩陣相乘的結果 if(Cols!=b.Rows){ //兩個矩陣能相乘的先決條件:第一個的列數等於第二個的行數 cerr<<"Incompatible matrices"<<endl; return Result; } int *rowSize=new int[b.Rows]; //b矩陣每行的非零元素個數 int *rowStart=new int[b.Rows+1]; //b矩陣每行第一個非零元素在b中的下標;為何加一? int *temp=new int[b.Cols]; // 暫時存放Result每一行每個元素的運算結果 int i,Current,lastInResult,RowA,ColA,ColB; //Current:a的指標; lastInResult:Result的指標 for(i=0;i<b.Rows;i++) //對roeSize陣列賦值 rowSize[i]=0; for(i=0;i<b.Terms;i++) rowSize[b.smArray[i].row]++; rowStart[0]=0; //對rowStart陣列賦值 for(i=1;i<b.Rows;i++) rowStart[i]=rowStart[i-1]+rowSize[i-1]; Current=0; //從下標0開始遍歷a lastInResult=-1; //賦初值-1是為了計算方便,看完程式碼即可瞭解 while(Current<Terms){ //遍歷三元組a的每一個元素 RowA=smArray[Current].row; //取得第一個元素的所在行 for(i=0;i<b.Cols;i++) //把temp陣列賦初值為0; temp[i]=0; while(Current<Terms&&smArray[Current].row==RowA){ //對該行的所有元素進行操作 ColA=smArray[Current].col; //該元素所在的列ColA就是該元素對應相乘的b中元素的行數 for(i=rowStart[ColA];i<rowStart[ColA+1];i++){ //遍歷b中該行的所有元素 ColB=b.smArray[i].col; //a的該元素與b中對應行第ColB列的元素相乘的結果應該被放到temp[ColB]中; temp[ColB]+=smArray[Current].value*b.smArray[i].value; } Current++; //a中該元素的已經完成使命,指向a中下一個元素 } for(i=0;i<b.Cols;i++){ //把該行的運算結果存入Result裡面 if(temp[i]!=0){ lastInResult++; Result.smArray[lastInResult].row=smArray[Current].row; Result.smArray[lastInResult].col=i; Result.smArray[lastInResult].value=temp[i]; } } } Result.Rows=Rows; //對Result的性質進行賦值操作 Result.Cols=b.Cols; Result.Terms=lastInResult+1; delete[] rowSize; //釋放new建立的儲存空間 delete[] rowStart; delete[] temp; return Result; }