对称矩阵、稀疏矩阵的压缩存储

1)对称矩阵的压缩存储

对称矩阵顾名思义就是符合行和列的个数相同,并且矩阵中存储的数据上三角和下三角中对应位置上的元素值是相等的。为了能够减少存储的空间,我们可以只存储上三角矩阵、或者下三角矩阵中的元素,这样就能够极大地节省空间的浪费。下面是对称矩阵的示列:

假设对称矩阵为n*n,这里以行优先存储下三角矩阵,总共需要存储的元素有n*(n+1)/2个元素,从而将n*n个元素压缩到n*(n+1)/2大小的空间中。

下面是具体的程序实现:

——symmetric.h文件

//实现对称矩阵
#include <assert.h>
template <class T>

//稀疏矩阵的存储需要n*(n + 1) / 2 个空间,将对称矩阵的下三角矩阵存储在一个一维数组中
class Matrix
{
public:
    Matrix(T* arr, size_t size)     //构造函数
        :_array(new T[size * (size + 1) / 2])
        , _size(size * (size + 1) / 2)
    {
      assert(arr);
      size_t num = 0;
      for (size_t i = 0; i < size; i++)
      {
         for (size_t j = 0; j < size; j++)
        {
            if (i >= j)
           {
               _array[num++] = arr[i * size + j];
           }
           else
           {
               break;           //减少循环遍历上三角矩阵中的元素
           }
         }
      }
   }
   
   T& Access(size_t i, size_t j)        //打印矩阵中某一元素
   {
      if (i < j)
      {
          swap(i, j);
      }
      return _array[i * (i + 1) / 2 + j];
   }
   
    void Display()    //打印
   {
       for (size_t i = 0; i < _size; i++)
       {
           cout << _array[i] << " ";
        }
       cout << endl;
    }
    
protected:
    T* _array;
    size_t _size;
};

void Test1()
{
   int arr[5][5] = {
                   { 0, 1, 2, 3, 4 },
                   { 1, 0, 1, 2, 3 },
                   { 2, 1, 0, 1, 2 },
                   { 3, 2, 1, 0, 1 },
                   { 4, 3, 2, 1, 0 } 
                 };
   Matrix<int> s1((int*)arr, 5);
   int ret = s1.Access(2, 1);
 
   s1.Display();
   cout << ret << endl;
}

2)稀疏矩阵的压缩存储

稀疏矩阵是指矩阵中大多数元素为无效数据的矩阵,即就是矩阵中的有效元素远远少于无效元素。对于稀疏矩阵我们应该怎样对其进行存储?稀疏矩阵没有对称矩阵那样上三角矩阵与其下三角矩阵的元素是对应相等的特点,不能像对称矩阵一样只存储上三角或者下三角矩阵中的元素,但是稀疏矩阵最大的特点就是矩阵中所需要的数据远远少于无效的数据,所以我们可以采取只存储有效的数据,将有效数据的行、列和值同时进行存储。下面为存储的图示:

下面为三元组表的类型如下:

struct Point
     {
          int _row;      //行
          int _col;       //列
          T _value;     //值

};

稀疏矩阵的存储问题解决了,那么矩阵的转置又应该怎么解决?

方法一:列序递增转置法

采用按照被转置矩阵三元组表_array的列序(即转置后三元组表的行序)递增的顺序进行转置,并依次送入转置后矩阵的三元组表中。具体的做法就是:将从开始以行进行遍历三元组表_array,找出其中所有列为1的元组,转置后进行存储。接着找出所有列为2的元组,转置后进行存储。依次类推...

方法二:一次定位快速算法

这个算法需要创建两个数组分别保存三元组表中第i列中非零元素的个数,存放转置前三元组表中第i列中第一个非零元素在三元组表B中的存储位置。下面为算法具体的图解:

下面是具体的程序实现:

——sparse.h文件

//实现稀疏矩阵的存储(存储点的位置信息(行、列、值))
#include <assert.h>
#include <vector>     //容器

template <class T>
struct Point
{
    int _row;
    int _col;
    T _value;
    
    Point(int row = 0, int col = 0, const T& value = T())     //构造节点
        :_row(row)
        , _col(col)
        , _value(value)
    { }
};

template <class T>
class Matrix
{
public:
    Matrix()
       :_array(NULL)
       , _cols(0)
       , _rows(0)
       , _invalues(0)
    { }
    
    Matrix(T* arr, int row, int col, const T& invalue)      //构造函数,invalue为无效值
   {
       for (size_t i = 0; i < row; i++)
      {
         for (size_t j = 0; j < col; j++)
         {
            if (arr[i * col + j] != invalue)
            {
               _array.push_back(Point<T>(i, j, arr[i * col + j]));   //将有效值压入容器中
            }
          }
       }
       _rows = row;
       _cols = col;
       _invalues = invalue;
    }
    
    void Display()    //打印稀疏矩阵
   {
       size_t index = 0;          //index记录——array中元素
       for (int i = 0; i < _rows; i++)
       {
           for (int j = 0; j < _cols; j++)
          {
     //从坐标(0,0)位置开始以行遍历,若坐标的i,j与存储的有效数据的坐标相同,进行打印,
     //若不同,此位置上输出非有效值。
              if (index < _array.size()
                    && _array[index]._row == i 
                    && _array[index]._col == j)
              {
                  cout << _array[index]._value << " ";
                  index++;
               }
              else
             {
                  cout << _invalues << " ";
              }
          }
          cout << endl;
       }
    }
    
    Matrix<T> Transport()        //将稀疏矩阵进行转置
    {
        Matrix<T> tmp;        //新建一个对象将行和列进行交换
        tmp._invalues = _invalues;
        tmp._cols = _rows;
        tmp._rows = _cols;
  /*
  上面将矩阵中的元素进行行列互换,但是存在矩阵存储时有效元素的顺序不一致的问题,
  通过对原来的矩阵进行以列进行遍历,当遇到与数组中存储的有效数据的列相同的,将其行列互换,进行存储。
  */
        for (size_t i = 0; i < _cols; i++)
        {
            size_t index = 0;
            while (index < _array.size())
           {
               if (_array[index]._col == i)
              {
                  Point<T> ptr;    //将有效数据的行和列进行交换存储
                  ptr._row = _array[index]._col;
                  ptr._col = _array[index]._row;
                  ptr._value = _array[index]._value;
                  tmp._array.push_back(ptr);
              }
              index++;
           }
        }
       return tmp;
    }
    
    /*快速转置的思想是将原来矩阵中每行的有效数据和每行开始的位置相加,
      能够直接确定有效数据在一维数组中的存储位置,然后直接进行行列交换*/
    Matrix<T> FastTransport()         //快速转置
    {
        Matrix<T> tmp;        //新建一个对象将行列进行交换
        tmp._invalues = _invalues;
        tmp._cols = _rows;
        tmp._rows = _cols;
        tmp._array.resize(_array.size());    //resize进行申请空间
        
        //_rowcount记录每列的有效数据个数,即就是原来矩阵每行的有效数据个数
        int* _rowcount = new int[_cols];    
        int* _rowstart = new int[_cols];   //_rowstart记录每行开始的位置
        memset(_rowcount, 0, sizeof(int)*_cols);
        memset(_rowstart, 0, sizeof(int)*_cols);
        size_t index = 0;
        while (index < _array.size())
       {
           _rowcount[_array[index]._col]++;
           index++;
        }
        
        _rowstart[0] = 0;   //记录开始位置
        for (size_t i = 1; i < _cols; i++)
       {
            _rowstart[i] = _rowstart[i - 1] + _rowcount[i - 1];
        }
        index = 0;
        while (index < _array.size())
       {
           int& rowstarts = _rowstart[_array[index]._col];
           Point<T> ptr;
           ptr._col = _array[index]._row;
           ptr._row = _array[index]._col;
           ptr._value = _array[index]._value;
           tmp._array[rowstarts++] = ptr;
           index++;
       }
       delete[] _rowcount;
       delete[] _rowstart;
       return tmp;
    }
    
protected:
    vector<Point<T>> _array;
    size_t _rows;
    size_t _cols;
    T _invalues;
};

void Test1()
{
    int arr[4][5] = {
                       { 0, 1, 2, 0, 0 },
                       { 1, 0, 1, 2, 0 },
                       { 0, 0, 0, 0, 0 },
                       { 0, 0, 0, 0, 0 },
                    };
 
    Matrix<int> s1((int*)arr, 4, 5, 0);
    s1.Display();
    cout << endl << endl;
 
    Matrix<int> tmp = s1.Transport();
    tmp.Display();
    cout << endl << endl;

    Matrix<int> ptr = s1.FastTransport();
    ptr.Display();
}
时间: 2024-10-11 21:25:31

对称矩阵、稀疏矩阵的压缩存储的相关文章

稀疏矩阵的压缩存储和转置

1.稀疏矩阵:M*N的矩阵,矩阵中有效值的个数远小于无效值的个数,且这些数据的分布没有规律. 2.稀疏矩阵的压缩存储:压缩存储值存储极少数的有效数据. 由于非零元素分布没有任何规律,所以在进行压缩存储的时侯需要存储无效值的同时还要存储有效元素在矩阵中的位置,即有效元素所在的行号和列号,也就是在存储某个元素比如aij的值的同时,还需要存储该元素所在的行号i和它的列号j,这样就构成了一个三元组(i,j,aij)的线性表. 使用{ row, col, value }三元组存储每一个有效数据,三元组按原

c++稀疏矩阵的压缩存储

稀疏矩阵 M*N的矩阵 其中有效值的个数远小于无效值的个数 且分布没有规律 Eg: int array [6][5] =     {{1, 0, 3, 0, 5}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {2, 0, 4, 0, 6}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}}; 稀疏矩阵的压缩存储 压缩存储值存储极少数的有效数据.使用{row,col,value}//行 列 值三元组存储每一个有效 数据,三元组按原矩阵中的位置,以行优先级

稀疏矩阵的压缩存储及转置

没有经过处理的稀疏矩阵其实就是一个特殊的二维数组,数组中的大部分元素是0或者其他类型的非法值,只有少数几个非零元素. 为了实现压缩存储,可以只存储稀疏矩阵的非0元素.在存储稀疏矩阵中的非0元素时,必须要存储该元素的行列号以及元素值.我们可以封装一个三元组类来存储这些元素. //三元组 template<class T> struct Triple { size_t _row;   //行 size_t _col;   //列 T _value;      //值 Triple<T>

C++实现稀疏矩阵的压缩存储、转置、快速转置

/*稀疏矩阵的压缩存储.转置.快速转置*/ #include <iostream> using namespace std; #include <vector> //三元组 template<class T> struct Triple { size_t _row; size_t _col; T _value; Triple(size_t row = 0, size_t col = 0, const T& value = T()) :_row(row) ,_co

稀疏矩阵的压缩存储与转置

稀疏矩阵:矩阵中大多数元素为0的矩阵(本文以行序为主序) 稀疏矩阵的三元组表述法: 类型结构: template <typename T> struct Triple { int _row; int _col; T _value; }; template <typename T> class SparseMatrix { public: SparseMatrix<T>::SparseMatrix(); SparseMatrix(const T* array, size_

1483 稀疏矩阵的压缩存储与相乘

1 //稀疏矩阵乘法 行逻辑链接的三元组顺序表 2 // 3 4 3 // 6 4 // 1 1 3 5 // 1 2 2 6 // 1 3 3 7 // 1 4 5 8 // 2 2 -1 9 // 3 1 2 10 // 4 2 11 // 5 12 // 1 2 2 13 // 2 1 1 14 // 3 1 -2 15 // 3 2 4 16 // 4 1 2 17 #include <iostream> 18 #include <cstring> 19 #define M

【数据结构】稀疏结构及稀疏矩阵的压缩存储,矩阵的转置

在矩阵中,有一类很重要的矩阵,就是-----稀疏矩阵. 所谓的稀疏矩阵呢,就是指的是,在矩阵中,有效的数据个数远远小于无效的数据个数(并且这些数据排列顺序没有规律).我们下面先举个稀疏矩阵的例子: 有效数据个数仅仅6个,其余都为无效数据0. 那我们将稀疏矩阵存在压缩矩阵中,设定一个三元组,使用{row,col,value}存储每一个有效数据,三元组按原矩阵中的位置,以行优先级先后顺序依次存放. 我们建立一个结构体: struct Triple//定义一个三元组,用来存储稀疏矩阵的x,y,坐标值

稀疏矩阵的压缩存储

    压缩存储值存储极少数的有效数据.使用{row,col,value}三元组存储每一个有效数据,三元组按原矩阵中的位置,以行优先级先后顺序依次存放. #define _CRT_SECURE_NO_WARNINGS 1 #include <vector> #include<iostream> using namespace std; //三元组的定义 template<class T> struct Triple { T _value; size_t _row; si

稀疏矩阵的压缩存储及快速转置

当一个矩阵为稀疏矩阵时,有效数据的个数比无效数据要少得多,因此若将一个矩阵全部存储会浪费空间,可以只将有效数据存储起来,无效数据作为标记 代码如下: #include <iostream> #include <vector> using namespace std; //可用一个三元组来存储有效数据的信息 template<class T> struct Triple {  size_t _row;  size_t _col;  T _value; }; //系数矩阵类