在c ++中创建矩阵的正确方法

时间:2009-03-06 11:23:44

标签: c++ data-structures stl graph matrix

我想为图形创建一个邻接矩阵。由于我读到使用matrix[x][y]形式的数组是不安全的,因为它们不检查范围,我决定使用stl的向量模板类。我需要存储在矩阵中的是布尔值。所以我的问题是,如果使用std::vector<std::vector<bool>* >*会产生太多开销,或者是否有更简单的矩阵方式以及如何正确初始化它。

编辑:非常感谢快速解答。我刚才意识到,那当然我不需要任何指针。矩阵的大小将在开始时初始化,并且在程序结束之前不会更改。这是一个学校项目,所以如果我写“好”代码会很好,虽然技术上性能不是太重要。使用STL很好。使用像boost这样的东西可能不受欢迎。

10 个答案:

答案 0 :(得分:18)

请注意,您也可以使用boost.ublas进行矩阵创建和操作,还可以使用boost.graph以多种方式表示和操作图形,以及使用算法等等。

编辑:无论如何,为您的目的进行矢量的范围检查版本并不困难:

template <typename T>
class BoundsMatrix
{
        std::vector<T> inner_;
        unsigned int dimx_, dimy_;

public:
        BoundsMatrix (unsigned int dimx, unsigned int dimy)
                : dimx_ (dimx), dimy_ (dimy)
        {
                inner_.resize (dimx_*dimy_);
        }

        T& operator()(unsigned int x, unsigned int y)
        {
                if (x >= dimx_ || y>= dimy_)
                        throw std::out_of_range("matrix indices out of range"); // ouch
                return inner_[dimx_*y + x];
        }
};

请注意,您还需要添加运算符和/或迭代器的const版本以及异常的奇怪用法,但您明白了。

答案 1 :(得分:10)

标准向量默认不进行范围检查。

即。 operator []不进行范围检查。

()的方法类似于[],但会进行范围检查 它会在超出范围的情况下抛出异常。

std::vector::at()
std::vector::operator[]()

其他说明: 为什么向量&lt;指针&gt; ?
你可以很容易地得到一个矢量&lt; Object&gt;。现在无需担心内存管理(即泄漏)。

std::vector<std::vector<bool> >   m;

注意:vector&lt; bool&gt;超载并且效率不高(即这种结构针对尺寸而非速度进行了优化)(现在标准委员会认为这可能是一个错误)。

如果在编译时知道矩阵的大小,可以使用std :: bitset?

std::vector<std::bitset<5> >    m;

或者如果是运行时定义的,请使用boost :: dynamic_bitset

std::vector<boost::dynamic_bitset>  m;

以上所有内容都允许您这样做:

m[6][3] = true;

答案 2 :(得分:8)

最佳方式:

创建自己的矩阵类,这样就可以控制它的每个方面,包括范围检查。

例如。如果您喜欢“[x] [y]”表示法,请执行以下操作:

class my_matrix {
  std::vector<std::vector<bool> >m;
public:
  my_matrix(unsigned int x, unsigned int y) {
    m.resize(x, std::vector<bool>(y,false));
  }
  class matrix_row {
    std::vector<bool>& row;
  public:
    matrix_row(std::vector<bool>& r) : row(r) {
    }
    bool& operator[](unsigned int y) {
      return row.at(y);
    }
  };
  matrix_row& operator[](unsigned int x) {
    return matrix_row(m.at(x));
  }
};
// Example usage
my_matrix mm(100,100);
mm[10][10] = true;

NB。如果你这样编程,那么C ++就像所有其他“安全”语言一样安全。

答案 3 :(得分:5)

如果你想要'C'数组性能,但是增加了安全性和类似STL的语义(迭代器,begin()&amp; end()等),请使用boost::array

基本上它是'C'数组的模板包装器,带有一些NDEBUG - 禁用范围检查断言(以及一些std::range_error异常抛出访问器)。

我使用像

这样的东西
boost::array<boost::array<float,4>,4> m;

而不是

float m[4][4];

一直都很有效(使用适当的typedef来保持详细程度,无论如何)。


更新:在此处的评论中对boost::array vs boost::multi_array的相对效果进行了一些讨论后,我会指出此代码是使用{{1在带有1333MHz DDR3 RAM的Q9450上的Debian / Lenny amd64上g++ -O3 -DNDEBUG需要3.3s而boost::multi_array需要0.6s。

boost::array

答案 4 :(得分:3)

我要做的是创建我自己的处理矩阵的类(可能作为一个数组[x * y],因为我更习惯于C(我有自己的边界检查),但你可以使用向量或该类中的任何其他子结构。)

首先让你的东西运作起来,然后担心它的运行速度。如果你正确地设计了类,你可以拉出你的数组[x * y]实现,并用向量或位掩码或任何你想要的东西替换它,而不用改变代码的其余部分。

我并不完全确定,但我认为类是什么意思,能够将实现抽象出来并且仅提供接口: - )

答案 5 :(得分:3)

除了到目前为止发布的所有答案之外,您最好还是查看C++ FAQ Lite。问题13.10 - 13.1216.16 - 16.19涵盖了与滚动自己的矩阵类相关的几个主题。您将看到存储数据的几种不同方法以及如何最好地编写下标运算符的建议。

此外,如果您的图表足够稀疏,您可能根本不需要矩阵。您可以使用std::multimap将每个顶点映射到它连接的顶点。

答案 6 :(得分:3)

我最喜欢的存储图表的方式是vector<set<int>>;向量中的n个元素(节点0..n-1),&gt; =每个集合中的0个元素(边缘)。只是不要忘记添加每个双向边的反向副本。

答案 7 :(得分:1)

还要考虑你的图形/矩阵有多大,性能是否很重要?图表是静态的,还是可以随时间增长,例如通过添加新边缘?

答案 8 :(得分:1)

请注意,std::vector也不会进行范围检查。

答案 9 :(得分:1)

可能不相关,因为这是一个老问题,但您可以使用Armadillo库,它提供了许多面向线性代数的数据类型和函数。

以下是您的具体问题的示例:

// In C++11
Mat<bool> matrix = {  
    { true, true},
    { false, false},
};

// In C++98
Mat<bool> matrix;
matrix << true << true << endr
       << false << false << endr;