压缩c ++

时间:2015-07-19 17:19:12

标签: c++ matrix symmetric

让我们假设我们有一个simmetric矩阵。

 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(j >= size - i)

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

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

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

怎么可能实现呢?

2 个答案:

答案 0 :(得分: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]; }

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

答案 1 :(得分: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) ;
    } ;