稀疏矩陣的壓縮存儲和快速逆置

稀疏矩陣啊,就是矩陣中的有效元素很稀疏,稀疏到什麼程度呢?通常認爲矩陣中非零元素的總數比上矩陣所有元素總數的值小於等於0.05時,則稱該矩陣爲稀疏矩陣(sparse matrix)。

我們想,一少部分的有效元素就佔用大部分的地址空間,是不是很浪費,那麼我們就要想辦法讓其不浪費那麼多,就是壓縮存儲。之前我們寫過對稱矩陣的壓縮,那是因爲對稱矩陣的分佈很有規律,但是再看一眼稀疏矩陣,除了有效元素少一點,也沒有什麼規律,那麼我們就要把這些元素的行和列也保存進去,也就是定義一個結構體——三元組。

    template<class T>
    struct Trituple           //三元組
    {
        Trituple(size_t row, size_t col, const T& data)
        : _row(row)
        , _col(col)
        , _data(data)
        {}

        size_t _row;
        size_t _col;
        T _data;
    };

之後就是具體的壓縮了,也沒什麼難得,只需定義一個容器,然後將有效元素的三元組保存進去就行了,在這裏我們選擇的是vector。還原的過程也就是打印。也是用兩個循環嵌套,不過這裏需要注意一些細節問題,具體的代碼中都有註釋。

#include<iostream>
using namespace std;

#include<assert.h>
#include<vector>

template<class T>
class SparseMatrix
{
    template<class T>
    struct Trituple           //三元組
    {
        Trituple(size_t row, size_t col, const T& data)
        : _row(row)
        , _col(col)
        , _data(data)
        {}

        size_t _row;
        size_t _col;
        T _data;
    };

public:
    SparseMatrix()
    {}

    // 稀疏矩陣的壓縮存儲
    SparseMatrix(int* array, size_t row, size_t col, const T& invalid)
        : _row(row)
        , _col(col)
        , _invalid(invalid)
    {
        for (int i = 0; i < _row; i++)
        {
            for (int j = 0; j < _col; j++)
            {
                if (array[i*_col + j] != invalid)//數據有效
                {
                    Trituple<T> temp(i, j, array[i*_col + j]);
                    _vt.push_back(temp);
                }
            }
        }
    }

    // 訪問稀疏矩陣中row行col中的元素
    T& Access(int row, int col)
    {
        int index = 0;
        int size = _vt.size();//將其寫在外面,不必每一次循環都調用一次size函數
        for (; index <size; index++)
        {
            //注意:這裏拿來和row比較的是三元組中的行,不是稀疏矩陣的行數
            if (_vt[index]._row == row&&_vt[index]._col == col)
            {
                return _vt[index]._data;
            }
        }
        return _invalid;
    }

    // 還原稀疏矩陣
    template<class T>
    friend ostream& operator<<(ostream& _cout, SparseMatrix<T>& s)
    {
        int index = 0;//用來遍歷vector
        int size = s._vt.size();
        for (int i = 0; i < s._row; i++)
        {
            for (int j = 0; j < s._col; j++)
            {
                //如果三元組未遍歷完,並且該位置正好是有效數據,那麼輸出
                //注意:s----_sm之間的關係,小心,容易出錯
                if (index < size && s._vt[index]._row == i && s._vt[index]._col == j)
                {
                    cout << s._vt[index++]._data << " ";//注意將index++
                }
                else//輸出無效數據
                    cout << s._invalid << " ";
            }
            cout << endl;
        }
        return _cout;
    }

    // 實現稀疏矩陣的逆置,並給出時間複雜度:列數*有效元素個數
    SparseMatrix<T> Transprot()
    {
        SparseMatrix<T> temp;//創建一個臨時對象,保存逆置後的矩陣
        temp._row = _col;//將原矩陣的列數,給成新矩陣的行數
        temp._col = _row;
        temp._invalid = _invalid;

        for (size_t i = 0; i < _col; i++)//按列訪問
        {
            int index = 0;
            while (index < _vt.size())
            {
                Trituple<T> &t = _vt[index];//將原來的有效元素另存爲一個三元組結構體中
                if (t._col == i)//遍歷存儲有效數據的三元組結構體,找每一列的有效數據,保存
                {
                    temp._vt.push_back(Trituple<T>(t._col, t._row, t._data));
                }
                index++;
            }
        }
        return temp;
    }

    //實現稀疏矩陣的快速逆置,並給出時間複雜度
    SparseMatrix<T> FastTransprot()
    {
        SparseMatrix<T> temp;//定義一個臨時對象保存逆置後的矩陣
        temp._row = _col;
        temp._col = _row;

        //統計原矩陣中每一列的有效個數:[2 0 2 0 2]
        int* pCount = new int[_col];
        memset(pCount, 0, _col*sizeof(int));

        int index = 0;
        while (index < _vt.size())
        {
            pCount[_vt[index]._col]++;
            index++;
        }

        // 原矩陣中的每一列的有效數據在新矩陣中的地址:[0 2 2 4 4]
        int *pAdd = new int[_col];
        memset(pAdd, 0, _col*sizeof(int));
        for (size_t i = 1; i < _col; i++)
        {
            pAdd[i] = pAdd[i - 1] + pCount[i - 1];
        }

        //放置元素
        index = 0;
        Trituple<T> &t = _vt[index];
        while (index<_vt.size())
        {
            //error:Debug Assertion Failed!   可能使用了野指針????
            temp._vt[pAdd[t._col]] = Trituple<T>(t._row, t._col, t._data);
            pAdd[t._col]++;
            index++;
        }

        delete[] pCount;
        delete[] pAdd;

        return temp;
    }


    // 實現稀疏矩陣的加法操作
    SparseMatrix<T> operator+(const SparseMatrix<T>& sp)
    {
        assert(_row == sp._row);
        assert(_col == sp._col);//兩個矩陣規格相同才能相加

        SparseMatrix<T> sum;//定義一個和的矩陣,規格和原矩陣一樣
        sum._row = _row;
        sum._col = _col;
        sum._invalid = _invalid;

        int iL = 0;//用來遍歷存儲有效元素的三元組
        int iR = 0;
        int iLAdd = 0;//有效元素在原矩陣中的地址
        int iRAdd = 0;
        while (iL < _vt.size() && iR < sp._vt.size())
        {
            iLAdd = _vt[iL]._row*_col + _vt[iL]._col;
            iRAdd = sp._vt[iR]._row*_col + sp._vt[iR]._col;

            if (iLAdd < iRAdd)
            {
                sum._vt.push_back(_vt[iL++]);
                continue;
            }
            else if (iLAdd > iRAdd)
            {
                sum._vt.push_back(sp._vt[iL++]);
                continue;
            }
            else
            {
                T data = _vt[iL]._data + sp._vt[iR]._data;
                if (data != _invalid)
                {
                    sum._vt.push_back(Trituple<T>(_vt[iL]._row, _vt[iL]._col, data));
                    iL++;
                    iR++;
                }
            }
        }
        if (!_vt.empty())
        {
            while (iL < _vt.size())
            {
                sum._vt.push_back(_vt[iL++]);
            }
            while (iR < _vt.size())
            {
                sum._vt.push_back(sp._vt[iR++]);
            }
        }
        return sum;
    }

private:
    vector<Trituple<T>> _vt; //用vector來保存有效數據的三元組
    size_t _row;//稀疏矩陣的行數
    size_t _col;//稀疏矩陣的列數
    T _invalid;//無效值
};

void FunTest()
{
    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 a1[6][5] =  {
        { 1, 0, 3, 0, 5 },
        { 0, 5, 0, 7, 0 },
        { 0, 0, 0, 0, 0 },
        { 2, 0, 4, 0, 6 },
        { 0, 0, 0, 0, 0 },
        { 0, 0, 0, 0, 0 } };

    int a2[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, 4, 0, 2, 0 } };

    SparseMatrix<int> s((int *)a, 6, 5, 0);

    //SparseMatrix<int> s1((int *)a1, 6, 5, 0);

    //SparseMatrix<int> s2((int *)a2, 6, 5, 0);

    cout << s << endl;//稀疏矩陣還原

    //cout<<s.Access(3, 2)<<endl;

    //std::cout << s.Transprot() << endl;

    cout << s.FastTransprot() << endl;

    //cout << s1 << endl;
    //cout << endl << s1 << endl;

    //cout << endl<< s1 + s2 << endl;
}

int main()
{
    FunTest();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章