【问题标题】:C++ Upper Triangular Matrix Bracket OperatorC++ 上三角矩阵括号运算符
【发布时间】:2015-04-01 07:33:05
【问题描述】:

我的某个项目遇到了障碍。我想创建一个上三角矩阵(对角线以下的所有元素都为零),它只分配保存非零元素所需的内存。我遇到的问题是索引到这个矩阵。我宁愿不必重新设计矩阵,但如果这是唯一的解决方案,那么我可以接受。附带说明一下,Vector 是我自己的实现,而不是 stl Vector。

到目前为止,我的类声明如下:

template <class T>
class UMatrix : public AbstractMatrix<T>
{
  private:
    Vector<T>* m_data;
    int m_size;
  public:
    //lots of member functions
};

上三角矩阵的构造函数:

template <class T>
UMatrix<T>(const int size)
{
  m_size = size;

  if(size < 1)
    throw(RangeErr(size));

  m_data = new Vector<T> [size];
  for(int i = 0; i < size; i++)
  {
    Vector<T> init(i + 1);
    m_data[i] = init;
  }
}

还有我遇到问题的代码:

template <class T>
Vector<T>& operator[] (const int index)
{
  if(m_data != NULL && index >= 0 && index < m_rows)
  {
    // Insert dark magic here
  }
  else
  {
    throw(RangeErr(index));
  }
}

这会产生一个交错向量数组,每个向量的长度都比前一个大 1。

我正在尝试实现括号运算符,以便UMatrix[a][b] 访问真正的上三角矩阵的 a 行、b 列。这意味着UMatrix[a][b] == 0a &gt; b

括号运算符也是抽象基类的虚函数,必须返回一个Vector&。此外,此实现必须使用方括号运算符,而不是 function () 运算符,以便与以前编写的代码兼容。我知道使用密集矩阵会更简单,但我仅限于必要的内存使用。

我的第一次尝试涉及使用一个向量进行存储,类似于一维数组矩阵。但是,括号运算符似乎也不可能为该实现编写。

我的问题:是否有可能实现这个括号运算符?

【问题讨论】:

  • new Vector 通常是错误的。为什么不只是有一个矢量对象?要制作 2d [] 运算符,您必须使用代理对象。添加带有任意数量参数的operator() 会更容易。

标签: c++ matrix operator-keyword square-bracket


【解决方案1】:

好吧,我不知道这是否是可接受的解决方案,因为您没有提供任何关于 Vector 类的信息。您可以创建另一个类,我们称之为SparseVector&lt;U&gt;,您将在其中拥有这样的代码

virtual U& operator[](int i) {
    if(m_data != nullptr) {
        if(m_nnzb <= i && i <= m_nnze) {
            return m_data[i - m_nnzb];
        }
    }
    throw std::runtime_error("bad index: in SparseVector::operator[]");
}

这里是这个实现的想法。这是一个大小为m_size 的向量,我们只存储从m_nnzbm_nnze 范围内的非零元素。我们将这个类用于矩阵类中的下标运算符。这是带有小示例的完整代码。

#include <iostream>
#include <exception>
#include <stdexcept>

/* vector interface */
template<typename T>
class IVector {
public:
    virtual T& operator[](int i) = 0;
};

/* matrix interface */
template<typename T>
class IMatrix {
public:
    virtual IVector<T>& operator[](int i) = 0;
};

/* implementation for upper triangular matrix */
template<typename T>
class UpperMatrix : public IMatrix<T> {
public:
    /* implementation for sparse vector */
    template<typename U>
    class SparseVector : public IVector<U> {
    public:
        SparseVector() {
            m_size = m_nnzb = m_nnze = 0;
            m_data = nullptr;
        }
        SparseVector(int size, int b, int e) {
            m_size = size;
            m_nnzb = b;
            m_nnze = e;
            m_data = new U[e - b];
        }
        SparseVector(const SparseVector<U>& other) {
            m_size = other.m_size;
            m_nnzb = other.m_nnzb;
            m_nnze = other.m_nnze;
            m_data = new U[m_nnze - m_nnzb];
            for(int i = 0; i < m_nnze - m_nnzb; ++i) {
                m_data[i] = other.m_data[i];
            }
        }
        virtual U& operator[](int i) {
            if(m_data != nullptr) {
                if(m_nnzb <= i && i <= m_nnze) {
                    return m_data[i - m_nnzb];
                }
            }
            throw std::runtime_error("bad index: in SparseVector::operator[]");
        }
    protected:
        int m_size;
        int m_nnzb;
        int m_nnze;
        U*  m_data;
    };
    UpperMatrix(int n) {
        m_size = n;
        m_data = new SparseVector<T>[n];
        for(int i = 0; i < n; ++i) {
            m_data[i] = SparseVector<T>(n, i, n);
        }
    }
    virtual IVector<T>& operator[](int i) {
        if(i < m_size && m_data != nullptr) {
            return m_data[i];
        }
        throw std::runtime_error("bad index in UpperMatrix::operator[]");
    }
protected:
    int              m_size;
    SparseVector<T>* m_data;
};

int main(int argc, char** argv) {
    UpperMatrix<int> m1(3);
    /* correct index */
    for(int i = 0; i < 3; ++i) {
        for(int j = i; j < 3; ++j) {
            m1[i][j] = i + j;
        }
    }
    for(int i = 0; i < 3; ++i) {
        for(int j = i; j < 3; ++j) {
            std::cout << m1[i][j] << " ";
        }
        std::cout << std::endl;
    }
    /* incorrect index */
    try {
        for(int i = 0; i < 3; ++i) {
            for(int j = 0; j < 3; ++j) {
                m1[i][j] = i + j;
            }
        }
    } catch(const std::exception& ex) {
        std::cout << "error occured: " << ex.what() << std::endl;
    }
}

【讨论】:

  • 这种方法的问题甚至在于名称:我不应该使用内存来存储非零值以外的任何内容。但是,我认为我已经通过使用从 Vector 继承的反向向量类解决了我的问题。唯一的区别是括号运算符返回m_data[m_size - index] 而不是m_data[index]
  • @DanielGrooms 只有两个整数有问题吗?
  • 想象一下:Matrix&lt;int&gt; large(10000);。这就是稀疏内存存储的问题。
  • @DanielGrooms 1) 我不需要任何想象,但您需要计算:假设我们有大小为 n = 1000 的上三角矩阵,因此有 500000 个非零值(1000 *1000 / 2) 并存储它我们需要额外的 2000 个整数。但它们占用的存储空间不到 1%(2000 / 502000 = 0.39%)!你认为这很重要吗? 2)您的问题是“甚至可以实现这个括号运算符吗?”。我提供了一个解决方案,我没有说没有其他解决方案。我已经向您展示了您需要创建另一个 Vector 类,这就是重点,但您也看不到它。
【解决方案2】:

教授更改了项目规范以允许括号运算符重载。这是解决此问题的最佳方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-03
    • 2011-06-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多