泛型矩阵类

矩阵就不用再解释了,写成泛型主要是为了几个方便:
1、方便在栈上分配空间。由于维度在编译期已知,所以可以做到在栈上分配空间。当然如果这个对象是new出来的,自然是在堆上分配,这里说的是在栈上分配这个对象时,矩阵元素所占用的空间也在栈上分配。
2、方便在编译期检查非法的矩阵运算。C++模板的强大推导能力可以在编译期推导出结果矩阵的维度。
3、泛型类在方法内联上具有优势。

这个矩阵类为了能够直接从数组赋值,使用了一个ArrayPorxy类(可参考《Imperfect C++》)。

代码如下:

template  < class  T,  int  D1,  int  D2 = 1 >
class  ArrayProxy
{
    T
*  data;
public :
    ArrayProxy(T (
& value)[D1][D2])
        : data(
& value[ 0 ][ 0 ])
    {
    }

    ArrayProxy(T (
& value)[D1 * D2])
        : data(value)
    {
    }

    T
*  getData()  const
    {
        
return  data;
    }
};

这个只是简单的实现。

因为我基本上不使用这个矩阵类,所以只完成几个简单功能:
1、从数组赋值:
int a[][3] = {{1,2,3}, {4,5,6}};
Matrix<int, 2, 3> m1(a);

int a[] = {1,2,3, 4,5,6};
Matrix<int, 2, 3> m1(a);
Matrix<int, 3, 2> m2(a);
Matrix<int, 6, 1> m3(a);
Matrix<int, 1, 6> m4(a);

2、矩阵乘法:
Matrix<int, 2, 3> m1;
Matrix<int, 2, 4> m2;
// m1 * m2  <== 编译错误,维度不匹配
Matrix<int, 3, 5> m3;
Matrix<int, 2, 5> m4 = m1 * m3; // <== 合法
// m3 * m1; // <== 编译错误,维度不匹配

源码如下:

template  < class  T,  int  R,  int  C >
class  Matrix
{
    T matrix[R][C];

public :
    
//  Big threedot.gif
    Matrix( void )
    {
        memset(matrix, 
0 sizeof (matrix));
    }

    Matrix(
const  Matrix &  rhs)
    {
        memcpy(matrix, rhs.matrix, 
sizeof (matrix));
    }

    Matrix
&   operator   = ( const  Matrix &  rhs)
    {
        memcpy(matrix, rhs.matrix, 
sizeof (matrix));
        
return   * this ;
    }

public :
    Matrix(
const  ArrayProxy < T,R,C >&  arr)
    {
        memcpy(matrix, arr.getData(), 
sizeof (matrix));
    }

    
~ Matrix( void )
    {
    }

public :
    T 
get ( int  r,  int  c)  const
    {
        assert(c 
<  C  &&  c  >=   0   &&  r  <  R  &&  r  >=   0 );
        
return  matrix[r][c];
    }

    
void   set ( int  r,  int  c, T v)
    {
        assert(c 
<  C  &&  c  >=   0   &&  r  <  R  &&  r  >=   0 );
        matrix[r][c] 
=  v;
    }

    
int  getCols ()  const
    {
        
return  C;
    }

    
int  getRows ()  const
    {
        
return  R;
    }

    
bool   operator   ==  ( const  Matrix &  rhs) const
    {
        
return  memcmp(matrix, rhs.matrix,  sizeof (matrix))  ==   0 ;
    }

    
bool   operator   !=  ( const  Matrix &  rhs) const
    {
        
return   ! ( * this   ==  rhs);
    }
};

template 
< class  T,  int  R,  int  C,  int  C1 >
Matrix
< T,R,C1 >   operator *  ( const  Matrix < T,R,C >&  lhs,  const  Matrix < T,C,C1 >&  rhs)
{
    Matrix
< T,R,C1 >  result;
    
for  ( int  r = 0 ; r < R;  ++ r)
    {
        
for  ( int  c = 0 ; c < C1;  ++ c)
        {
            
int  value  =   0 ;
            
for  ( int  i = 0 ; i < C;  ++ i)
            {
                value 
+=  lhs. get (r,i)  *  rhs. get (i,c);
            }
            result.
set (r,c,value);
        }
    }
    
return  result;
}

测试代码:

int  main()
{
    {
        
//  测试初始化
        Matrix < int 3 4 >  m1;
        Matrix
< int 3 4 >  m2(m1);
        Matrix
< int 3 4 >  m3  =  m1;
        Matrix
< int 3 4 >  m4;
        m4 
=  m1;

        
for  ( int  i = 0 ; i < 3 ; i ++ )
            
for  ( int  j = 0 ; j < 4 ; j ++ )
            {
                assert (m1.
get (i, j)  ==   0 );
                assert (m2.
get (i, j)  ==   0 );
                assert (m3.
get (i, j)  ==   0 );
                assert (m4.
get (i, j)  ==   0 );
            }

        
int  a[]  =  { 1 , 2 , 3 , 4 5 , 6 , 7 , 8 9 , 10 , 11 , 12 };
        Matrix
< int 3 4 >  m5(a);

        
int  b[ 3 ][ 4 =  { { 1 , 2 , 3 , 4 },
                        {
5 , 6 , 7 , 8 },
                        {
9 , 10 , 11 , 12 }};

        Matrix
< int 3 4 >  m6(b);

        Matrix
< int 3 4 >  m7(m5);
        Matrix
< int 3 4 >  m8  =  m5;
        Matrix
< int 3 4 >  m9;
        m9 
=  m5;

        
for  ( int  i = 0 ; i < 3 ; i ++ )
            
for  ( int  j = 0 ; j < 4 ; j ++ )
            {
                assert (m5.
get (i, j)  ==  i * 4 + j + 1 );
                assert (m6.
get (i, j)  ==  i * 4 + j + 1 );
                assert (m7.
get (i, j)  ==  i * 4 + j + 1 );
                assert (m8.
get (i, j)  ==  i * 4 + j + 1 );
                assert (m9.
get (i, j)  ==  i * 4 + j + 1 );
            }

        
//  维数不匹配,编译错误
        
//  Matrix<int, 4, 5> m10 = m9;
         int  c[][ 2 =  {{ 1 , 2 }, { 2 , 3 }};
        
//  数组大小不匹配,编译错误
        
// Matrix<int, 3, 4> m10(c);
         int  d[]  =  { 1 , 2 };
        
//  数组大小不匹配,编译错误
        
// Matrix<int, 3, 4> m11(d);

        
//  乘法维数不合适,无法相乘
        
// m1 * m2;

        Matrix
< int , 4 , 3 >  m12;
        
//  匹配,可以相乘
        Matrix < int 3 3 >  m13  =  m1  *  m12;

        Matrix
< int 8 3 >  m14;
        
//  无法相乘
        
// Matrix<int, 3, 3> m15 = m1 * m14;
        
//  可以相乘
        Matrix < int 8 4 >  m15  =  m14  *  m1;
    }

    {
        
//  检查点乘
         int  a[ 2 ][ 5 =  {{ 1 , 2 , 3 , 4 , 5 }, { 6 , 7 , 8 , 9 , 10 }};
        Matrix
< int 2 5 >  m1(a);

        
int  b[ 5 ][ 3 =  {{ 1 , 2 , 3 }, { 4 , 5 , 6 }, { 7 , 8 , 9 }, { 10 , 11 , 12 }, { 13 , 14 , 15 }};
        Matrix
< int 5 3 >  m2(b);

        
int  c[ 2 ][ 3 =  {{ 135 , 150 , 165 }, { 310 , 350 , 390 }};
        Matrix
< int 2 3 >  m3(c);

        Matrix
< int 2 3 >  m4  =  m1  *  m2;
        assert(m4 
==  m3);

        cout 
<<  m4. get ( 0 , 0 <<  endl;
    }

    
return   0 ;
}

补充:
1、加法、减法只需要2个矩阵维度相同即可。
template  < class  T,  class  R,  class  C >
Matrix
< T,R,C >   operator +  ( const  Matrix < T,R,C >&  lhs,  const  Matrix < T,R,C >&  rhs)
{
   
//  dot.gif
}

2、由于1x1的矩阵可以看成一个标量,矩阵与标量运算结果维数与原矩阵相同,可以重载来实现。
template  < class  T,  class  R,  class  C >
Matrix
< T,R,C >   operator *  ( const  Matrix < T,R,C >&  lhs,  const  Matrix<T,1,1> &  rhs)
{
    
//  dot.gif
}

3、由于类型泛化,可能某些合理的运算无法进行,比如float型矩阵,与一个int型标量运算等。这些最好是借助类型萃取等手段,推导出运算以后的类型。(c++0x中包含自动获取运算结果类型的关键字typeof,等几年就可以用了:)。GCC编译器中已有实现,不过似乎有BUG)。

4、其它。泛型实现可能会有一些考虑不周的地方,强类型有强类型的好处,不过必须要有完整的泛型算法支撑,否则难以使用。也可以把泛型矩阵类从一个普通矩阵类派生,这样更容易写出通用算法,不过在实现上可能要借助于运行期多态,对于矩阵类来说并不合适。

5、其它。。前面说C++的模板相当强大,D语言模板到目前为止似乎已经完全实现了C++模板的功能,还增加了一些比如字符串值参模板等特性,比C++模板功能更多。在代码编写上,由于可以编写静态判断语句(编译期)以及静态断言,编写模板比C++更容易。有时间可以试试用它写个矩阵类,纯粹是兴趣,这些东西真的很难用到,现成的库也挺多。

6、其它。。。c++0x要提供“template typedef”,也就是可以这样定义:
template <int R, int C> typedef Matrix<int, R, C> MatrixInt;  // 定义类型,维度不定
template <class T> typedef Matrix<T, 4, 4> Matrix4x4; // 定义维度,类型不定
由此可以出定义行向量、列向量、标量等,当然实际使用起来可能没那么舒服了。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是实现泛型矩阵的基本运算的代码,其中包括矩阵和方阵的实现,以及主函数。 ```cpp #include <iostream> #include <cstdlib> #include <ctime> using namespace std; template <typename T> class Matrix { protected: int m, n; T **data; public: Matrix(int m, int n) { this->m = m; this->n = n; data = new T *[m]; for (int i = 0; i < m; i++) { data[i] = new T[n]; for (int j = 0; j < n; j++) { data[i][j] = 0; } } } Matrix(const Matrix &matrix) { m = matrix.m; n = matrix.n; data = new T *[m]; for (int i = 0; i < m; i++) { data[i] = new T[n]; for (int j = 0; j < n; j++) { data[i][j] = matrix.data[i][j]; } } } virtual ~Matrix() { for (int i = 0; i < m; i++) { delete[] data[i]; } delete[] data; } Matrix &operator=(const Matrix &matrix) { if (&matrix != this) { for (int i = 0; i < m; i++) { delete[] data[i]; } delete[] data; m = matrix.m; n = matrix.n; data = new T *[m]; for (int i = 0; i < m; i++) { data[i] = new T[n]; for (int j = 0; j < n; j++) { data[i][j] = matrix.data[i][j]; } } } return *this; } Matrix operator+(const Matrix &matrix) const { Matrix result(m, n); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { result.data[i][j] = data[i][j] + matrix.data[i][j]; } } return result; } Matrix operator-(const Matrix &matrix) const { Matrix result(m, n); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { result.data[i][j] = data[i][j] - matrix.data[i][j]; } } return result; } void show() const { for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { cout << data[i][j] << "\t"; } cout << endl; } } }; template <typename T> class SquareMatrix : public Matrix<T> { public: SquareMatrix(int n) : Matrix<T>(n, n) { } SquareMatrix(const SquareMatrix &matrix) : Matrix<T>(matrix) { } T determinant() const { if (this->n == 1) { return this->data[0][0]; } else if (this->n == 2) { return this->data[0][0] * this->data[1][1] - this->data[0][1] * this->data[1][0]; } else { T det = 0; for (int i = 0; i < this->n; i++) { SquareMatrix submatrix(this->n - 1); for (int j = 1; j < this->n; j++) { for (int k = 0; k < this->n; k++) { if (k < i) { submatrix.data[j - 1][k] = this->data[j][k]; } else if (k > i) { submatrix.data[j - 1][k - 1] = this->data[j][k]; } } } T subdet = submatrix.determinant(); if (i % 2 == 0) { det += this->data[0][i] * subdet; } else { det -= this->data[0][i] * subdet; } } return det; } } SquareMatrix operator*(const SquareMatrix &matrix) const { if (this->n != matrix.m) { throw "Invalid matrix dimensions"; } SquareMatrix result(this->n); for (int i = 0; i < this->n; i++) { for (int j = 0; j < this->n; j++) { T sum = 0; for (int k = 0; k < this->n; k++) { sum += this->data[i][k] * matrix.data[k][j]; } result.data[i][j] = sum; } } return result; } void printLeftProduct(const Matrix<T> &matrix) const { if (this->n != matrix.m) { throw "Invalid matrix dimensions"; } SquareMatrix result(this->n); for (int i = 0; i < this->n; i++) { for (int j = 0; j < matrix.n; j++) { T sum = 0; for (int k = 0; k < this->n; k++) { sum += this->data[i][k] * matrix.data[k][j]; } cout << sum << "\t"; } cout << endl; } } }; int main() { srand(time(NULL)); Matrix<int> A(5, 6); Matrix<int> B(5, 6); Matrix<int> C(5, 6); for (int i = 0; i < 5; i++) { for (int j = 0; j < 6; j++) { A.data[i][j] = rand() % 10; B.data[i][j] = rand() % 10; C.data[i][j] = rand() % 10; } } cout << "A:" << endl; A.show(); cout << "B:" << endl; B.show(); cout << "C:" << endl; C.show(); cout << "A + B:" << endl; (A + B).show(); cout << "A - C:" << endl; (A - C).show(); SquareMatrix<int> D(4); SquareMatrix<int> E(4); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { D.data[i][j] = rand() % 10; E.data[i][j] = rand() % 10; } } cout << "D:" << endl; D.show(); cout << "E:" << endl; E.show(); cout << "D * E:" << endl; (D * E).show(); cout << "det(D) = " << D.determinant() << endl; cout << "det(E) = " << E.determinant() << endl; try { cout << "D * A:" << endl; D.printLeftProduct(A); } catch (const char *msg) { cerr << msg << endl; } return 0; } ``` 这段代码实现了一个泛型矩阵 `Matrix` 和一个方阵 `SquareMatrix`,其中 `SquareMatrix` 是 `Matrix` 的派生。`Matrix` 实现了矩阵加减法和打印矩阵的功能,`SquareMatrix` 实现了计算行列式和矩阵乘法的功能,并增加了判断矩阵规格是否匹配的检查,以及打印左乘矩阵的功能。主函数中随机生成了两个矩阵和两个方阵,并进行了加减法、乘法和求行列式等操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值