原创

数据结构——矩阵

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/austin_anzheng/article/details/53377551

                                     数据结构——矩阵

 1.1矩阵类

     1.定义

template<class T>
class Matrix{
	private:
		int rows, cols;     // 矩阵的行数和列数
		T *element; 	     // 矩阵的元素
	public:
		Matrix(int r = 0, int c = 0); 		 // 构造函数
		Matrix(const Matrix<T>& m); 	 // 复制构造函数 
		~Matrix() {delete [] element; } 	 // 析构函数
		int Rows() const {return rows; } 	 // 返回矩阵行数
		int Columns() const {return cols; }  // 返回矩阵列数
T & operator() (int i, int j) const; 	// 重载下标操作符
Matrix<T>& operator = (const Matrix<T>& m); // 重载赋值运算符
Matrix<T> operator +() const; 		// 重载一元加法运算符
Matrix<T> operator +(const Matrix<T> & m) const; // 重载二元加法运算符
Matrix<T> operator -() const;       		// 重载一元减法运算符
Matrix<T> operator -(const Matrix<T> & m) const; // 重载二元减法运算符
Matrix<T> operator *(const Matrix<T> & m) const; // 重载乘法运算符
Matrix<T> operator +=(const T& x); 		// 重载增值运算符
};

    2.重载乘法运算符:(时间复杂性为O(rows*cols*m.cols) .)

template<class T>
Matrix<T> Matrix<T>:: operator * ( const Matrix<T> & m) const 
{	if ( cols != m.rows ) 
		{cout << “Size not matched” <<endl; exit(1);}
	Matrix<T> w (rows, m.cols); // 创建一个临时矩阵,存放二矩阵相乘的结果
	int ct = 0, cm = 0, cw = 0; 	 // 设定初始位置
	for ( int i =1 ; i <= rows; i++ ){
		for ( int j = 1 ; j <= m.cols ; j++ )
		{	T sum = element[ct]*m.element[cm] ;
			for ( int k = 2 ; k <= cols ; k++ )
				{ ct++;        // 指向*this第i行的下一个元素
				  cm += m.cols;     // 指向m第j列的下一个元素
				  sum += element[ct] * m.element[cm]; 
				}
           w.element[cw] = sum; // 保存计算得到的w(i,j)值
		  cw++;
		  ct – = cols–1; 	// 重新指向本行的行首元素
		  cm = j; 		// 指向m第j+1列的列首元素
		}
		ct += cols; 		// 指向下一行的行首元素
		cm = 0; 		// 重新指向第一列的列首元素
		}
	return w;
 }



1.2特殊矩阵

       1.对角矩阵的压缩存储
         若n*n的方阵M是对角矩阵,则对所有的i≠j (0<i<n, 0<j<n) 都有M(i, j)=0,即非对角线上的元素均为0 . 
         对于一个nn维对角矩阵,至多只有n个非零元素,因此只需存储其n个对角元素的信息。
         采用一维数组d[n]来压缩存储对角矩阵,其中d[i]存储M[i, i]的值。 

       2.三角矩阵的压缩存储(以下三角矩阵为例)

           考虑一个n*n维下三角矩阵,其第一行有1个非零元素,第二行有2个非零元素,…,第n行有n个非零元素,非零元素共有(1+2+…+n) = n(n+1)/2个。可以用大小为n(n+1)/2的一维数组来存储下三角矩阵,即把下三角矩阵M的非零元素映射到一个一维数组d中。映射次序可采用按行优先或按列优先。

          设元素M(i, j)前面有k个元素,可以计算出 k =1+2+…+ (i *1) + (j*1)= i(i*1)/2 + (j*1)。设一维数组d的下标是从0开始,则M(i, j)映射到d中所对应的元素是d[k] . 有了k的计算公式,可以很容易实现下三角矩阵的压缩存储。 

       3.对称矩阵的压缩存储

          因为对称矩阵中M(i, j)与M(j, i)的信息相同,所以只需存储M的上三角部分或下三角部分的元素信息。
          参照下三角矩阵的压缩存储方法,即用大小为n(n+1)/2的一维数组来存储,对于对称矩阵中的下三角矩阵元素M(i, j) (i*j) ,和下三角矩阵压缩存储的映射公式一样,映射到d[k] (其中k = i(i*1)/2 + (j*1) );对于对称矩阵中的上三角矩阵元素M(i, j) (i<j,不包含对角线上矩阵元素) ,因其元素值与下三角中的M(j, i)相同,故映射到d[q](其中q= j(j*1)/2 + (i*1)). 有了k和q的计算公式,即可实现对称矩阵的压缩存储。 

       4.稀疏矩阵的压缩存储

         (1) 定义:设矩阵非零元素的个数远远小于零元素的个数,则称 A 为稀疏矩阵。
     ◆  特点:零元素的分布一般没有规律。
     ◆  作用:解决空间浪费的问题。

         (2)   存储非零节点:由三个域(行号、列号和元素值)构成的结点被称为三元组结点:矩阵的每个非零元素可由一个三元组结点(i,j,aij)唯一确定。

         (3)存储稀疏矩阵的方法:

                    a. 用顺序存储方式实现的三元组表(将表示稀疏矩阵的非零元素的三元组结点按行优先的顺序排列,得到一个线性表,将此线性表用顺序存储结构存储起来,称之为三元组表。)     

                   
                    b. 链接存储方式实现的十字链表。

           (4)类声明

 template <class T> // 三元组的结点类
 class Trituple
 { 
    firend class SparseMatrix;
    private:
       int row, col;       // 非零元素的行号、列号
       T value;             // 非零元素的值
  };
template <class T> // 稀疏矩阵类的声明
class SparseMatrix
   {  
     private:
     // 稀疏矩阵的行数、列数及非零元素个数
       int Rows, Cols, Count;
		   // 存储三元组表的数组
       int MaxTerm;
       Trituple <T> smArray[MaxTerm];   
	public:
    // 建立一个稀疏矩阵
    SparseMatrix( int Mrows,int Mcols);
    // 求转置矩阵
    SparseMatrix <T> Transpose( );
    // 求矩阵的和
    SparseMatrix <T> Add(SparseMatrix <T> b);
    // 求矩阵的乘积
    SparseMatrix <T>
    Multiply(SparseMatrix <T> b);
};	

         (5)类实现

template <class T> // 求转置矩阵    
SparseMatrix <T>SparseMatrix::Transpose( )
 { 
   SparseMatrix <T> b; //  声明一个稀疏矩阵b
   b.Rows = Cols; //  b的行数等于原矩阵的列数
   b.Cols = Rows; //  b的列数等于原矩阵的行数
   b.Count = Count; //  b与原矩阵的非零元素个数相同
   if ( Count > 0 ) //  若有非零元素{ int Bnubmer = 0;
 for(k=0;k<Cols;k++)
    for(i=0;i<Count;i++)
        if(smArray[i].col==k)
           { b.smArray[Bnumber].row=k;
             b.smArray[Bnumber].col=
             smArray[i].row;
             b.smArray[Bnumber].value=
             smArray[i].value;
             Bnumber++;}
           }
          return b; // 返回转置矩阵 b
  }

可知:;循环次数为A′(A的转置矩阵)的行数n,执行次数是矩阵非零元素个数t,显然,求转置矩阵的时间复杂性为O(nt) .

        (6)十字链表 

                  矩阵的元素结构如下:分别表示该元素的左邻非零元素、上邻非零元素、所在的行、所在的列和它的值。

           矩阵的每一行、每一列都设置为由一个表头结点引导的循环链表,并且各行和各列的表头结点有如下特点:
      -1 = COL(Loc(BASEROW[i]))< 0
      -1 = ROW(Loc(BASECOL[j]))< 0

                                                         十字链表为:

                 若某一行没有非零元素,则  LEFT(BASEROW[i])=BASEROW[i]
                 若某一列没有非零元素,则   UP(BASECOL[i])=BASECOL[i]


                  综上可知:   对矩阵的运算实质上就是在十字链表中插入结点、删除结点以及改变某个结点的 VAL 域的值。

                               实现算法:

//ADL语言实现算法
算法 SP(BASE,PIVOT)
// 稀疏矩阵的主步骤操作,稀疏矩阵的表示方式为正交链表,指针变量PIVOT
// 指向主元素,一维数组PTR[1:n]是指针型
SP1 [初始化,确定主行I0,主列J0 ]
    I0←ROW(PIVOT)  .  J0←COL(PIVOT)  .  
    α←1.0 / VAL(PIVOT)  .  VAL(PIVOT) ←1.0  .  
    P0←Loc(BASEROW[I0])  .  Q0←Loc (BASECOL[J0])  .
SP2 [处理主行I0]
    P0←LEFT(P0)  .  J←COL(P0)  .  
    IF J<0 THEN GOTO SP3.
    ELSE (PTR[J] ←Loc(BASECOL[J])  .
                VAL(P0) ←α* VAL(P0)  .
                GOTO SP2. )  .
SP3 [找新行I,并指定P1]
    Q0←UP(Q0)  .  I←ROW (Q0)  .  
    IF I<0 THEN RETURN  .
    IF I=I0 THEN  GOTO  SP3  .
    P←Loc(BASEROW[I]) .  P1←LEFT(P) .
SP4 [确定新列J]
    P0←LEFT(P0) .  J←COL(P0) .  
    IF J<0 THEN (VAL(Q0)← -α* VAL(Q0) .
                              GOTO SP3. )  .
    IF J=J0  THEN GOTO SP4  .
SP5 [P1所指元素所在的列与J列比较]
    WHILE  COL(P1) > J DO  
        (P←P1 .  P1←LEFT(P)) . 
    IF COL(P1) =J  THEN GOTO SP7  .
SP6 [插入新元素]
    WHILE  ROW(UP(PTR[J])) > I DO  
        PTR[J]←UP(PTR[J]) . 
    X<=AVAIL  . VAL(X) VAL(Q0)VAL(P0) . 
    ROW(X) ←I .  COL(X) ←J . 
    LEFT(X) ← P1 .  UP(X) ←UP(PTR[J]) . 
    LEFT(P) X . P X. UP(PTR[J]) X . PTR[J] X .
    GOTO SP4.
SP7 [主步骤操作]
    VAL(P1) ←VAL(P1) - VAL(Q0)* VAL(P0) .
    IF VAL(P1)=0 THEN GOTO SP8 . 
    ELSE  (PTR[J]←P1 .  P←P1 .
                 P1←LEFT(P)  .  GOTO  SP4 .  )  . 
SP8 [删除零元素]
    WHILE  UP(PTR[J]) ≠ P1 DO  
        PTR[J]←UP(PTR[J]) . 
    UP(PTR[J])←UP(P1) .  LEFT(P)←LEFT(P1) . 
    AVAIL <= P1  .  P1 ←LEFT(P) . 
    GOTO SP4. ▐ 



文章最后发布于: 2016-11-28 14:47:16
展开阅读全文
0 个人打赏

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 1024 设计师: 上身试试

分享到微信朋友圈

×

扫一扫,手机浏览