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

原创 2016年05月30日 17:18:34

在矩阵中,有一类很重要的矩阵,就是-----稀疏矩阵。


所谓的稀疏矩阵呢,就是指的是,在矩阵中,有效的数据个数远远小于无效的数据个数(并且这些数据排列顺序没有规律)。我们下面先举个稀疏矩阵的例子:

wKiom1cNoXqgYIYUAAAPLNUT7Mw525.png

有效数据个数仅仅6个,其余都为无效数据0.


那我们将稀疏矩阵存在压缩矩阵中,设定一个三元组,使用{row,col,value}存储每一个有效数据,三元组按原矩阵中的位置,以行优先级先后顺序依次存放。

我们建立一个结构体:

struct Triple//定义一个三元组,用来存储稀疏矩阵的x,y,坐标值
{
    int _row;
    int _col;
    T _value;
};

将每一个有效数据(三元组)存在顺序表vector中,打印数据就按照顺序表的特点打印。

矩阵的转置:


wKiom1cNoyLgdIoCAAAda7pd8GI613.png

所以,转置就是将原矩阵的行、列对换,也就是将[i][j]和[j][i]位置上的数据对换。


代码如下:


#include<vector>

template<class T>
struct Triple//定义一个三元组,用来存储稀疏矩阵的x,y,坐标值
{
    int _row;
    int _col;
    T _value;

    Triple(int row, int col, int value)
        :_row(row)
        , _col(col)
        , _value(value)
    {}
};



template<class T>
class SparseMatrix
{
public:
    SparseMatrix(T* a, int m, int n, const T& invalid)
        
    {
        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (invalid != a[i*n+j])
                {
                         //将每一个有效数据(三元组)存在顺序表vector中
                    Triple <T> tmp(i, j, a[i*n + j]);
                    
                    _a.push_back(tmp);                    
                }
                
            }
        }    
    }


    //用坐标形式打印稀疏矩阵
    void Display(int m, int n, const T& invalid)
    {
        cout << "用坐标形式打印稀疏矩阵" << endl;
        cout <<"{" <<"x," << "  " << "y," << "  " << "value" <<"}" <<endl;
        for (int k = 0; k < _a.size(); k++)
        {
  
          cout << "{" << _a[k]._row << ",  " << 
_a[k]._col << ",  " << _a[k]._value << "  " << 
"}" << endl;
        }                                
    }

    //用矩阵形式打印稀疏矩阵
    void DisplayMatrix(int m, int n, const T& invalid)
    {        
        cout << "用矩阵形式打印稀疏矩阵" << endl;
        int k = 0;
        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < n; j++)
            {        
                
                if (k<_a.size()&&_a[k]._row == i && _a[k]._col == j)
                {
                    cout << _a[k]._value << "  ";
                    k++;
                }
                else
                {
                    cout << invalid << "  ";
                }                                
            }
            cout << endl;
        }
    }
    
    SparseMatrix<T> Transport(T* a, int m, int n, const T& invalid);

protected:
    vector <Triple <T>> _a;
    
};



void Test()
{

    int a[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 },
                  }; 

    int m = 6;
    int n = 5;
    SparseMatrix<int> sm((int*)a, m, n, 0);
    sm.Display( m, n, 0);
    sm.DisplayMatrix( m, n, 0);
    SparseMatrix<int> sm1((int*)a, m, n, 0);
    sm1 = sm.Transport((int*)a, m, n, 0);

    
    sm1.Display( n, m, 0);
    sm1.DisplayMatrix(n, m, 0);
}

int main()
{
    Test();
    system("pause");
    return 0;
}

下面我们单独说说如何实现矩阵转置的代码:


现在我们知道,此时的矩阵不再是几乘几,而是以一个三元组Triple形式存储的。那我们就没有办法像线性代数中将矩阵的第一行放在新矩阵的第一列,以此重复。


而是换一种思路来想这个问题:

(1)转置后的矩阵第一列是由之前矩阵的第一行得来的。

(2)之前是行优先存储,现在要用列优先存储。


那我们现在想,是不是可以遍历矩阵的第0列分别拿该列的元素去与三元组中的元素比较是否满足是第0列。即:拿第0列元素,去与三元组比较,发现1,2是第0列。则把1,2按顺序存放在新的三元组中。再第一列,第二列,……时间复杂度:O(列数*有效数据个数)。


我们现在看下代码:

template<class T>
SparseMatrix<T> SparseMatrix<T>::Transport(T* a, int m, int n, const T& invalid)
{
    cout << "矩阵转置:" << endl;
    SparseMatrix<T> ret;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < _a.size(); j++)
        {
            if (_a[j]._col == i)
            {
                Triple<T> tri(_a[j]._col, _a[j]._row, _a[j]._value);
                ret._a.push_back(tri);
            }
        }
    }
    return ret;
}


快速转置:

思想是统计好转置后上一行的元素个数RowCounts,及转置后每行在压缩矩阵的起始位置RowStarts,由此确定下一行元素位置。

template<class T>
SparseMatrix<T> SparseMatrix<T>::FastTransport(int m, int n, const T& invalid)
{
    SparseMatrix<T> ret;
    ret._a.resize(_a.size());
        
    vector<int> RowCounts;     //转置后每行元素的个数
    RowCounts.resize(n);
    RowCounts.assign(n, 0);
    for (int i = 0; i < _a.size(); i++)
    {
        RowCounts[_a[i]._col]++;    //元素相同列的话,列号对应的顺序表加加
    }
        
    vector<int> RowStarts;
    RowStarts.resize(n);
    RowStarts.assign(n, 0);
    
    //下一行元素的起始位置等于上一行中的元素个数与上一行元素的起始位置之和
    for (int j = 0; j < n-1; j++) 
    {
        RowStarts[j + 1] = RowStarts[j] + RowCounts[j];
    }
     
    //行列数互换
    for (int k = 0; i < _a.size(); k++)
    {
        ret._a[RowStarts[_a[k]._col]]._col = _a[k]._row;
        ret._a[RowStarts[_a[k]._col]]._row = _a[k]._col;
        ret._a[RowStarts[_a[k]._col]++]._value = _a[k]._value;
    }
    return ret;
}

则:时间复杂度为:

2*元素个数+列数

即:O(元素个数+列数)

本文出自 “Han Jing's Blog” 博客,请务必保留此出处http://10740184.blog.51cto.com/10730184/1763284

稀疏矩阵的压缩存储及转置,快速转置法,C++代码实现

/*稀疏矩阵的压缩存储及转置*/ #include using namespace std; /*三元组顺序表的类型定义*/#define itemSize 100 typedef struct{  ...
  • hackerain
  • hackerain
  • 2010年10月20日 23:57
  • 3482

5.3矩阵的压缩存储(稀疏矩阵转置和快速转置)

5.3矩阵的压缩存储(稀疏矩阵转置和快速转置)
  • qq78442761
  • qq78442761
  • 2017年02月09日 15:22
  • 2938

【数据结构】稀疏矩阵的压缩存储和转置算法(C++代码)

稀疏矩阵的压缩存储和转置算法
  • u010834867
  • u010834867
  • 2017年04月06日 15:59
  • 1258

稀疏矩阵的快速转置和乘法运算源代码(非常详细)

/*sparseMatrix.h*/ #include "stdio.h" #include "stdlib.h" #define SIZE 100 typedef struct { in...
  • serena_0916
  • serena_0916
  • 2017年11月29日 08:20
  • 229

【LB】稀疏矩阵的快速转置原理及其算法

关于稀疏矩阵的快速转置法,首先得明白其是通过对三元表进行转置。如果误以为是对矩阵进行转置,毫无疑问就算你想破脑袋也想不出个所以然,别陷入死胡同了!          对于一个三元表,行为i,列为...
  • u013598542
  • u013598542
  • 2014年04月14日 22:30
  • 7396

稀疏矩阵的存储方式及其快速转置的实现

稀疏矩阵: M*N的矩阵,矩阵中有效值的个数远小于无效值的个数,且这些数据的分布没有规律。 如下图矩阵: 稀疏矩阵的压缩存储方式: 压缩存储极少数的有效数据。使用{row,col,value}...
  • xyzbaihaiping
  • xyzbaihaiping
  • 2016年04月19日 14:52
  • 1915

稀疏矩阵的快速转置(C语言版)

#include #include #define MAX 100 typedef struct node{     int i,j,v; }SYZ; void createlist(SYZ *L...
  • wanying2001
  • wanying2001
  • 2015年11月30日 21:10
  • 2280

C++实现矩阵压缩存储与(快速)转置

注意:以下所有代码均在VS2010环境下运行测试             了解了C语言以后,我们都知道,要存储一个矩阵,用一个二维数组即可实现,今天,由我来带领大家玩点新鲜的,对矩阵进行压缩存储并对其...
  • snow_5288
  • snow_5288
  • 2016年12月10日 19:05
  • 7846

稀疏矩阵基于“三元组”的转置算法实现

稀疏矩阵基于“三元组”的转置算法实现
  • wangchuanqi1234
  • wangchuanqi1234
  • 2016年04月11日 17:45
  • 1285

稀疏矩阵的普通转置与快速转置算法

稀疏矩阵的普通转置与快速转置算法 一般来说,对于系数矩阵,我们使用三元组来存储。即就是将矩阵的所有非零元素的三元组存放在一个顺序表中,如图所示: 注意一个转置的前提:该顺序表是排好序的,即行优...
  • qq845579063
  • qq845579063
  • 2016年05月09日 17:49
  • 3396
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【数据结构】稀疏结构及稀疏矩阵的压缩存储,矩阵的(快速)转置
举报原因:
原因补充:

(最多只允许输入30个字)