代码之家  ›  专栏  ›  技术社区  ›  Daniel Grooms

C++上三角矩阵括号运算符

  •  0
  • Daniel Grooms  · 技术社区  · 10 年前

    我的某个项目遇到了障碍。我想创建一个上三角矩阵(对角线下面的所有元素都是零),它只分配存储非零元素所需的内存。我遇到的问题是索引到这个矩阵中。我宁愿不必重新设计矩阵,但如果这是唯一的解决方案,那么我可以接受它。顺便说一句,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] == 0 什么时候 a > b .

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

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

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

    2 回复  |  直到 10 年前
        1
  •  0
  •   Nikolay K    10 年前

    嗯,我不知道这是不是可以接受的解决方案,因为你没有提供任何关于 Vector 班你可以创建另一个类,让我们调用它 SparseVector<U> ,在那里您将有这样的代码

    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_nnzb m_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;
        }
    }
    
        2
  •  -1
  •   Daniel Grooms    10 年前

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