稀疏矩阵的csr存储方式及其基本运算

csr矩阵的多样化构建以及加法与乘法运算

csr矩阵是比三元组效率还要高的矩阵存储方式,但实际上我用vector库并不能很好的体现出这一点。在python中,csr矩阵经常作为基本单元运算。

具体csr矩阵的情况参见以下代码。

ps:没事少整花活……

/*
<1> 设计算法实现稀疏矩阵的运算应用。
        要求:1)设计稀疏矩阵类;2)给出测试用例,实现n组稀疏矩阵的相加与相乘。
        CSR最优存储。
*/
#include
#include
#include
using namespace std;
class sparse_martix {
private:
    vector<int> Offset;//偏移量数列
    vector<int> Cloum;//列位置数列
    vector<int> Element;//元素数列
    int r;//行数
    int c;//列数
protected:
    void _creat_mar(string str) { //读取文件中稀疏矩阵到在线状态
        char a = ' ';
        char a1 = ' ';
        int f = 0;
        int j = 0;
        int i = 0;
        int e = 0;
        c = 0;
        ifstream infile;//以字符状态读取,获取行数,0元所在等信息
        ifstream infile2;//以整数状态读取,获取非零元的值
        infile.open(str);
        infile2.open(str);
        if (!infile.is_open()) {
            cout << "Error in Open infile!" << endl;
            exit(1);
        }
        else if (!infile2.is_open()) {
            cout << "Error in Open infile2!" << endl;
            exit(1);
        }
        else {
            cout << "Begin read files!" << endl;
        }
        Offset.push_back(f);//首行偏移量
        while (!infile.eof()) {
            infile >> noskipws >> a;//不跳过不可见字符
            if (a == ' ') {//遇到空格,说明是当前已经读完,开始进入下一个字符
                j++;
            }
            if (a != '\n' && a != ' ') {
                if (a1 == '\n' || a1 == ' ')
                    if (a != '0') {
                        Cloum.push_back(j);
                        f++;
                    }
            }
            a1 = a;
            if (a == '\n') {//换行,到下一行。
                Offset.push_back(f);
                if (j > c) {
                    c = j;
                }
                j = 0;
                i++;
            }
        }
        r = i - 1;
        while (!infile2.eof()) {
            infile2 >> e;
            if (e != 0) {
                Element.push_back(e);
            }
        }
        infile.close();
        infile2.close();
        cout << "Over!" << endl;
        return;
    }

    void show_mar() {
        bool flag = false;
        int f = 0;//控制偏移量数组的
        vector<int>::iterator it = this->Offset.begin();
        vector<int>::iterator ite = it + 1;
        while (ite != this->Offset.end() - 1) {
            if (*it != *ite) {
                for (int i1 = 0; i1 <= this->c; i1++) {//本次输出c+1个数。
                    flag = false;
                    for (int i = *it; i < *ite; i++) {
                        if (i1 == Cloum[i]) {//如果有里面的数
                            cout << Element[i] << ' '; //输
                            flag = true;
                            if (i1 == this->c) {
                                cout << endl;
                            }
                        }
                    }
                    if (flag == false) {
                        cout << 0 << ' ';
                        if (i1 == c) {
                            cout << endl;
                        }
                    }
                }
            }
            else {
                for (int i = 0; i <= c; i++) {
                    cout << 0 << ' ';
                }
                cout << endl;
            }
            it = ite;
            ite++;
        }
        return;
    }
public:
    sparse_martix(string str) {//文件读入。
        _creat_mar(str);
    }
    sparse_martix(int r, int c) {//创建R*C的空矩阵。
        this->r = r;
        this->c = c - 1;
        for (int i = 0; i <= r + 1; i++) {
            Offset.push_back(0);
        }
    }
    sparse_martix() {//什么都没有,建立{}矩阵。
        r = 0;
        c = 0;
        Offset.push_back(0);
        Cloum.push_back(0);
        Element.push_back(0);
    }
    sparse_martix(vector<vector<int>> a) {//二维容器建立。
        int f = 0;//偏离值
        int j = 0;//计数当前元素的列位置。
        int i = 0;
        c = 0;
        vector<vector<int>>::iterator iter = a.begin();
        vector<int>::iterator it = (*iter).begin();
        Offset.push_back(f);
        for (; iter != a.end(); iter++) {
            if (j > c)
                c = j - 1;
            j = 0;//新的一行,从0开始。
            i++;
            for (it = (*iter).begin(); it != (*iter).end(); it++) {
                if (*it != 0) {
                    Element.push_back(*it);
                    Cloum.push_back(j);
                    f++;
                }
                j++;//向下一个元素号挪动。
            }
            Offset.push_back(f);//存上本行偏离值。
        }
        r = i;
    }
    sparse_martix(sparse_martix& a) {//拷贝构造函数
        this->r = a.r;
        this->c = a.c;
        copy(a.Cloum.begin(), a.Cloum.end(), this->Cloum.begin());
        copy(a.Element.begin(), a.Element.end(), this->Element.begin());
        copy(a.Offset.begin(), a.Offset.end(), this->Offset.begin());
        return;
    }
    void show() {
        show_mar();
        return;
    }
    void midf() {
        vector<int>::iterator it = this->Cloum.begin();
        for (; it != Cloum.end(); it++) {
            cout << *it << " ";
        }
        cout << endl << c << " " << r << endl;
    }
    void plus(sparse_martix &a) {
        if (r != a.r || c != a.c) {
            cout << "不同型无法相加!" << endl;
            return ;
        }
        a.show();
        cout << '+' << endl;
        this->show();
        cout << "结果是:" << endl;
        sparse_martix s(r, c + 1);
         int cs = 1;
         vector<int>::iterator it = this->Offset.begin();
         vector<int>::iterator ite = it + 1;
         vector<int>::iterator its = a.Offset.begin();
         vector<int>::iterator ites = its + 1;
         while (ite != this->Offset.end() - 1 && ites != a.Offset.end() - 1) {
             if (*it != *ite && *its != *ites) {
                 if (*it == *ite) {
                     s.Offset[cs] = s.Offset[cs - 1] + (*ites - *its);
                     for (int i1 = *its; i1 < *ites - *its; i1++) { //本次处理被加矩阵非零数。
                         s.Element.push_back(a.Element[i1]);
                         s.Cloum.push_back(a.Cloum[i1]);
                     }
                     cs++;
                 }
                 else if (*its == *ites) {
                     s.Offset[cs] = s.Offset[cs - 1] + (*ite - *it);
                     for (int i1 = *it; i1 < *ite - *it; i1++) { //本次处理被加矩阵非零数。
                         s.Element.push_back(this->Element[i1]);
                         s.Cloum.push_back(this->Cloum[i1]);
                     }
                     cs++;
                 }
                 else {
                     s.Offset[cs] = s.Offset[cs - 1] + max(*ites - *its, *ite - *it);
                     int i2 = 0;
                     int i3 = 0;
                     for (int i1 = 0; i1 <= c; i1++) { //本次处理c+1个数。
                         if (*ite - *it > i2 && i1 == this->Cloum[*it + i2]) {
                             s.Cloum.push_back(this->Cloum[*it + i2]);
                             if (*ites - *its > i3 && this->Cloum[*it + i2] == a.Cloum[*its + i3]) {
                                 s.Element.push_back(this->Element[*it + i2] + a.Element[*its + i3]);
                                 i3++;
                                 i2++;
                             }
                             else {
                                 s.Element.push_back(this->Element[*it + i2]);
                                 i2++;
                             }
                         }
                         else if (*ites - *its > i3 && i1 == a.Cloum[*its + i3]) {
                             s.Element.push_back(a.Element[*its + i3]);
                             i3++;
                         }
                     }
                     cs++;
                 }
             }
             else {
                 s.Offset[cs] = s.Offset[cs - 1];
                 cs++;
             }
             if (ite != this->Offset.end() - 1 && ites != a.Offset.end() - 1) {
                 it = ite;
                 ite++;
                 its = ites;
                 ites++;
             }
         }
         s.show();
         return ;
    }
    void multy(sparse_martix& a) {
        if (this-> c + 1 != a.r ){
            cout << "不可乘!" << endl;
            return ;
        }
        sparse_martix s(r, a.c + 1);
        if (a.Element.empty()) {
            s.show();
            return;
        }
        if (this->Element.empty()) {
            s.show();
            return;
        }    
        int cs = 1;
        //for (vector::iterator it = a.Offset.begin(); it != a.Offset.end(); it++) {
        //    cout << *it << endl;
        //}
        vector<int>::iterator it = this->Offset.begin();
        vector<int>::iterator ite = it + 1;
        while (ite != this->Offset.end() - 1){//3行
            if (*it == *ite) {//有全零行。
                s.Offset[cs] = s.Offset[cs - 1];
            }
            else {
                int n3 = 0;//确定此行算完需要偏移的量。
                for (int j = 0; j <= a.c; j++) {//3列,j代表a的列数。确定结果矩阵的列数。
                    int n1 = 0;//第n1个元素,用来运算得到n2的变量,同时也是得到a中ele索引的变量
                    int n2 = 1;//第n2行,确定this矩阵的对应列数的变量
                    int x = 0;//this元素
                    int y = 0;//a元素
                    int sum = 0;//s的最终元素
                    vector<int>::iterator itr = a.Offset.begin();
                    for (vector<int>::iterator its = a.Cloum.begin(); its != a.Cloum.end(); its++, n1++) {
                        if (*its == j) {//如果找到本列非零元。
                            y = a.Element[n1];
                            n2 = 0;
                            itr = a.Offset.begin();
                            while (*itr <= n1) {//确定行数
                                n2++;
                                itr++;
                            }
                            bool flag = false;
                            for (int i = *it; i < *ite; i++) {//找到对应this元素
                                if (this->Cloum[i] == n2 - 1) {
                                    x = this->Element[i];
                                    flag = true;
                                    break;
                                }
                            }
                            if (flag) {//如果有对应元素。
                                sum += x * y;
                                flag = false;
                            }
                        }
                    }
                    if (sum != 0) {//如果该元素的确非零
                        s.Element.push_back(sum);
                        s.Cloum.push_back(j);
                        n3++;
                    }
                }
                s.Offset[cs] = s.Offset[cs - 1] + n3;
            }
            it = ite;
            ite++;
            cs++;
        }
        s.show();
        return;
    }
    void operator=(sparse_martix a) {
        this->r = a.r;
        this->c = a.c;
        copy(a.Cloum.begin(), a.Cloum.end(), this->Cloum.begin());
        copy(a.Element.begin(), a.Element.end(), this->Element.begin());
        copy(a.Offset.begin(), a.Offset.end(), this->Offset.begin());
        return;
    }
};
int main() {
    string str, str1;
    cout << "文件位置?" << endl;
    cin >> str >> str1;
    sparse_martix sm(str);
    sparse_martix sm1(str1);
    sm.multy(sm1);
    return 0;
}

需要注意的是:我们当前的矩阵最主要的时间耗费浪费在对齐上。如果想要高效地计算,重要方向就是如何使矩阵对齐变得简洁起来。

你可能感兴趣的:(c++,矩阵,算法,线性代数)