数据结构——矩阵

来源:互联网 发布:sftp 批量下载 java 编辑:程序博客网 时间:2024/06/02 00:17

                                     数据结构——矩阵

 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. ▐ 



0 0
原创粉丝点击