0

假设我们有一个对称矩阵。

 A=
    1 2 3
    2 6 4
    3 4 5

现在因为它是对称的,我们不需要在其中存储所有数字。让我们假设将 0 放在左下三角形的单元格中。

B = 
    1 2 3
    0 6 4
    0 0 5

如果我想访问 B 的 0 元素的内容,我需要做的就是反转感兴趣单元格的行和列:

if(i>j) val += L[j][i]    // ex: B[1][0] is stored in B[0][1]

(假设目标是总结所有未记忆的元素)

此时我们只使用了右上角的三角形,但实际上并没有节省内存,因为未使用的元素仍然分配了 0 值。

节省内存的一种方法是使用向量的向量:

vector<vector<int>> C;

并相应地调整每一行的大小。

C=
  1 2 3
  6 4
  5

通过这样做,我们不能再使用交换技巧了,因为您可能会注意到空元素现在位于矩阵的右下三角形中。

未分配的值是:

D=
   x x x
   x x 2
   x 3 4

在这种情况下,我们感兴趣的元素可以通过以下 if 条件找到:

if(j >= size - i)

现在的问题是识别 0 元素的正确内容。换句话说:

if(j >= size - i) ans += L[?][?]

所以例如,如果我在i=1 j=2我不应该访问元素 [1][2] 而是访问 [0][2] = 2 (等等 [2][1] -> [0][2] = 3,[2][2] -> [1][1] = 4)。

怎么可能实现呢?

4

2 回答 2

0

要将此类三角形数组存储在压缩线性向量中,我使用以下类。

#define ogf_array_check(index, data_size) assert(index < data_size)
#define ogf_assert(b) assert(b)
   /**
     * A 2d array of values aij where only the cells such 
     * that j <= i are represented.
     */
    template <class T> class TriangularArray {
    public:
        typedef TriangularArray<T> thisclass ;

        TriangularArray(int size) : size_(size), data_size_(size * (size + 1) / 2) {
            data_ = new T[data_size_] ;
        }
        ~TriangularArray() { delete[] data_; data_ = nil ; }

        int size() const { return size_ ; }
        int data_size() const { return data_size_ ; }

        /**
         * index0 denotes the line, and index1 the column,
         * note that index1 should be less-than or equal to
         * index0.
         */
        T& operator()(int index0, int index1) {
            ogf_array_check(index0, size_) ;
            ogf_array_check(index1, size_) ;
#ifdef OGF_ARRAY_BOUND_CHECK
            ogf_assert(index1 <= index0) ;
#endif
            int offset = index0 * (index0 + 1) / 2 ;
            return data_[offset + index1] ;
        }

        /**
         * index0 denotes the line, and index1 the column,
         * note that index1 should be lerr or equal to
         * index0.
         */
        const T& operator()(int index0, int index1) const {
            ogf_array_check(index0, size_) ;
            ogf_array_check(index1, size_) ;
#ifdef OGF_ARRAY_BOUND_CHECK
            ogf_assert(index1 <= index0) ;
#endif
            int offset = index0 * (index0 + 1) / 2 ;
            return data_[offset + index1] ;
        }

        void set_all(const T& value) {
            for(int i=0; i<data_size_; i++) {
                data_[i] = value ;
            }
        }

        T& from_linear_index(int index) {
            ogf_array_check(index, data_size_) ;
            return data_[index] ;
        }

        const T& from_linear_index(int index) const {
            ogf_array_check(index, data_size_) ;
            return data_[index] ;
        }

        T* data() const { return data_ ; }

    private:
        T* data_ ;
        int size_ ;
        int data_size_ ;

    private:
        TriangularArray(const thisclass& rhs) ;
        thisclass& operator=(const thisclass& rhs) ;
    } ;
于 2015-07-20T08:25:09.513 回答
0

您可以通过存储左下三角形并丢弃右上三角形来解决您的特定问题:

1
2 6
3 4 5

索引操作可以实现为:

int operator()(int r, int c) const { return r >= c ? L[r][c] : L[c][r]; }

如果您真的想按照您的建议以移位的方式存储矩阵的右上角三角形(请参阅C),那么您可以按以下方式访问矩阵元素:

int operator()(int r, int c) const { return c >= r ? L[r][c-r] : L[c][r-c]; }

但是,如果您真的想从压缩中获得一些收益,我建议将整个三角形打包在一个单一的一维向量中。拥有向量的向量反而会增加相当多的开销......

于 2015-07-19T18:40:06.723 回答