65.9K
CodeProject 正在变化。 阅读更多。
Home

C++ 矩阵类

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.33/5 (4投票s)

2011 年 10 月 24 日

CPOL

4分钟阅读

viewsIcon

60500

downloadIcon

185

关于 C++ 矩阵类的文章。

引言

在 C 和 C++ 中,二维数组表示为数组的数组。每个元素的数组类型相同,并且使用行优先顺序的数组下标运算符访问元素。例如,我们可以有

int array[10][10];
...
array[0][0] = 1;

二维数组在许多应用程序中都很有用,包括数学编程和数据表示。 例如,一个显示股票历史价格的系统可以使用矩阵来存储给定日期的数据点。 每列可以代表一天,每行可以代表一天的一组点。 在这样的系统中,人们可能很想使用 XML 流式传输数据; 但是,这不是必需的。 有时,XML 会增加数据处理时间并无谓地扩大传输数据的实际大小。

内置的二维数组有一些局限性。 特别是,它不能轻易地调整数组大小,也不允许程序员添加另一行或另一列。 添加和删除行和列的功能在表示类似电子表格的数据时非常有用。 例如,用户可能想添加另一组代表给定日期股票价格的数据点。 这促使创建了一个 C++ 矩阵类,该类旨在封装此行为。

背景

矩阵类是一个允许二维数组表示的类。 该类被开发为一个 C++ 模板,允许用户指定元素的基础类型。 但是,它使用向量的向量方法实现,这允许使用 C++ 数组下标运算符,就好像矩阵类是内置的数组的数组类型一样。 但是,该类保留了调整行和列大小的能力。

例如,以下是可能的(其中“d”是向量的向量)

d[i][j]=k++;

除了数组下标运算符支持外,该类还能够允许用户添加行或添加列,以及删除行或删除列。 例如,以下也是可能的

matrix<int> m(2,4);
...
// Test delete row
m.del_row(3);
cout < < m;
...
// Test add row
matrix<int>::matrix_row_t row;
row.resize(4);
for(int i = 0; i < 4; i++) {
     row[i]=100;
}
m.add_row(3,row);
cout < < m;

请注意代码如何不使用 XML 作为内部表示。 它而是依赖于 STL。 该类的核心实现基于以下逻辑

template < class T>
class matrix {
   public:
   typedef vector<vector<T> >matrix_t;
   typedef vector<T> matrix_row_t;
   typedef vector<T> matrix_col_t;
   ...
};

其中该类提供了以下用于添加和删除行或列的方法

void add_row(int _row, matrix_col_t &_col)
      throw(runtime_error);
void del_row(int _row);
void add_col(int _col, matrix_row_t &_row)
      throw(runtime_error);
void del_col(int _col);

执行添加行和添加列操作的代码比人们想象的稍微复杂一些,但仍然可读。 想法是首先创建一个临时矩阵,该临时矩阵的相应行或列的大小调整为一。 然后,代码通过首先将现有矩阵数据复制到调整大小的临时矩阵中,然后在适当的位置向其中添加新行或列来添加新行或列。 类似地,删除行或列需要创建一个调整大小的临时矩阵,并将我们要保留的字段复制到临时矩阵中。 在操作结束时,然后使用新的临时矩阵更新矩阵。 请注意,使用 XML 作为底层表示执行这些类型的操作不是必需的或高效的。 最好使用 STL 容器存储数据,并对这些容器执行操作。 作为说明,请考虑以下“add_row”的代码

void add_row(int _row, matrix_col_t &_col)
      throw(runtime_error)
   {
      if(_row >= (row + 1) || _row < 0) {
         throw runtime_error("matrix<T>::add_row:: row out-of-bounds");
      }
      matrix_t tmp;
      tmp.resize(row + 1);
      for(int i = 0; i < (row + 1); i++) {
         tmp[i].resize(col);
      }
      for(int i = 0; i < _row; i++) {
         for(int j = 0; j < col; j++) {
            tmp[i][j] = m[i][j];
         }
      }
      for(int j = 0; j < col; j++) {
         tmp[_row][j] = _col[j];
      }
      for(int i = _row + 1, ii = _row; ii < row; i++, ii++) {
         for(int j = 0; j < col; j++) {
            tmp[i][j] = m[ii][j];
         }
      }
      m = tmp;
      row = row + 1;
   }

此外,用户可以调整矩阵的行和列大小。 该类还支持用于调试的 ostream 运算符,并且有方法可以流式传输和流式输入数据以及以 html 格式转储输出的能力。

void resize(int _row, int _col);
friend
ostream &operator>>(ostream &out, matrix &obj);
string stream_out() const;
void stream_in(string _m);
string to_html() const;

Using the Code

该代码易于使用,并允许用户从类中添加和删除行和列,以及调整行和列的大小。 一个可能的用法示例是

   matrix<int> m(2,4);
   matrix<int>::matrix_t &d = m.get_data();
   int k = 0;
   for(int i = 0; i < m.get_row(); i++) {
      for(int j = 0; j < m.get_col(); j++) {
         d[i][j]=k++;
      }
   }
   cout << m;

关注点

该代码在不使用 XML 的情况下完成了内部数据的流式输入和流式输出。 当流式输出数据时,将输出行和列大小,然后以行优先顺序输出数据。 所有元素都使用单个空格字符分隔。 流式输入时,会读取行和列大小,并将数据从流中读取到矩阵中。 这使我们可以以紧凑的格式存储数据,并在必要时通过网络连接传输数据。 该类旨在保存整数和浮点数据。

使用 XML 流式传输数据实际上可能非常昂贵。 例如,如果矩阵有 1000 行和 1000 列,并且每个元素都表示一个整数,那么我们需要至少 1000000 字节来流式传输数据。 如果使用 XML 使用标记(例如

<point>0</point>

然后对于每个整数,我们将添加额外的 17 字节的数据。 此外,我们需要使用标记来识别行和列。 当然,这将需要使用 XML 处理器进行处理,这将进一步增加代码的处理时间和复杂性。 但是,查看矩阵类的流式输出和流式输入运算符,我们在空间和时间复杂性方面都具有以下简单高效的逻辑

string stream_out() const
   {
      ostringstream out;
      out << row << " " << col << " ";
      for(int i = 0; i < row; i++) {
         for(int j = 0; j < col; j++) {
            out << m[i][j] << " ";
         }
      }
      return out.str();
   }
   void stream_in(string _m)
   {
      istringstream in(_m,istringstream::in);
      in >> row;
      in >> col;
      m.resize(row);
      for(int i = 0; i < row; i++) {
         m[i].resize(col);
      }
      for(int i = 0; i < row; i++) {
         for(int j = 0; j < col; j++) {
            in >> m[i][j];
         }
      }
   }
© . All rights reserved.