[关闭]
@rg070836rg 2015-08-16T15:10:57.000000Z 字数 3414 阅读 1968

三元组

data_structure


首先先痛斥下vc6.0,并记住以后遇到模板类的,一定要全部重建。

一、介绍

如果在矩阵中,多数的元素为0,称此矩阵为稀疏矩阵(sparse matrix)。
概念很清楚,矩阵中,0元素比较多的矩阵是稀疏矩阵,
这样的矩阵可以用三元组以及十字链表存贮,这里介绍三元组的用法。

二、三元组介绍

含有在矩阵中的行列数,以及元素值的结构体。定义如下:

  1. template<class T>
  2. struct Triple
  3. {
  4. int r,c;
  5. T elem;
  6. bool operator <(const Triple<T>& rhs) const // 升序排序时必须写的函数
  7. {
  8. return r < rhs.r;
  9. }
  10. };

重载运算符是为了后面调用vector的排序,省的自己费心的按顺序插入,这样全部插好了,直接排序就好了。

三、稀疏矩阵

这是一个类,类里面包含行数,列数,还有非零元的个数,同时非零元的具体值,即三元组,用的是向量存储,动态扩容,随机访问复杂度为o(1),很强大的工具。

3.1构造函数的撰写

构造函数,我准备写两种形式,

  • 第一种无参,那就要求从键盘键入值,
  • 第二种有参,那数据来源是文件

3.1.1无参

先存储数据的个数,如行数,列数,非零元个数,然后循环读取数据,存入,并压入向量,最后对其排序。
最好能对重复元素位置做检测,这边没有实现这个功能,以后再补吧。

  1. template<class T>
  2. SparseMatrix<T>::SparseMatrix()
  3. {
  4. do {
  5. cout<<"请分别输入矩阵的行数、列数和非零元个数:\n";
  6. cout<<"行数:";
  7. cin>>this->row;
  8. cout<<"列数:";
  9. cin>>this->col;
  10. cout<<"非零元的个数:";
  11. cin>>this->num;
  12. if(this->row < 0 || this->col < 0 || this->num < 0 || this->num > this->row * this->col) cout<<"有错。。";
  13. } while(this->row < 0 || this->col < 0 || this->num < 0 || this->num > this->row * this->col);
  14. //保证了数据的正确性。。
  15. if (this->num==0) return ;//每个元素都是空的。
  16. for(int k =0;k<this->num;k++)
  17. {
  18. Triple<T> tmp;
  19. do {
  20. cout<<"请输入第"<<k+1<<"个非零元的行和列:\n";
  21. cout<<"行:";
  22. cin>>tmp.r;
  23. cout<<"列:";
  24. cin>>tmp.c;
  25. cout<<"元素:";
  26. cin>>tmp.elem;
  27. if(tmp.r <= 0 || tmp.r > this->row || tmp.c <= 0 || tmp.c > this->col) cout<<"有错。。重输";
  28. } while(tmp.r <= 0 || tmp.r > this->row || tmp.c <= 0 || tmp.c > this->col);//检测输入是否合法
  29. triList.push_back(tmp);
  30. }
  31. sort(triList.begin(), triList.end());
  32. /* for (int i=0;i<triList.size();i++)
  33. {
  34. cout<<triList[i].r<<" ";
  35. }
  36. */// std::sort(triList,0); !!!重要的,一定要排序或者想办法顺序插入。
  37. }

3.1.2有参构造函数

这边的数据,准备来源于文件,所以先介绍文件的格式

5
5 5
2 3 1
3 2 2
2 4 3
5 5 4
1 2 5

第一行为非零元个数
第二行是矩阵规模
后面是三元组的内容。
所以设计load函数也很方便。

  1. int num;
  2. int r;
  3. int c;
  4. Triple<int> * Load(char *fname)
  5. {
  6. ifstream fin(fname);
  7. int n;
  8. fin>>n;
  9. num=n;
  10. fin>>r;
  11. fin>>c;
  12. Triple<int> *list=new Triple<int> [n];
  13. int i=0;
  14. while(!fin.eof())
  15. {
  16. fin>>list[i].r;
  17. fin>>list[i].c;
  18. fin>>list[i++].elem;
  19. }
  20. fin.close();
  21. return list;
  22. }

全局变量num,r,c便于传递有参函数的参数,Load函数返回的是结构体数组,我们利用这个来构造矩阵。同样也需要判重,这边不写。

  1. template<class T>
  2. SparseMatrix<T>::SparseMatrix(int rs,int cs,int n,Triple<T> *list)
  3. {
  4. this->col=cs;
  5. this->row=rs;
  6. this->num=n;
  7. for (int i=0;i<n;i++)
  8. {
  9. Triple<T> tmp;
  10. tmp.r=list[i].r;
  11. tmp.c=list[i].c;
  12. tmp.elem=list[i].elem;
  13. triList.push_back(tmp);
  14. }
  15. sort(triList.begin(), triList.end());
  16. }

这样,调用的方式为
SparseMatrix<int> sm(r,c,num,Load("data.txt"));
但是很奇怪的是,
如果声明为:
SparseMatrix(Triple<T> *list,int rs,int cs,int n);
这样在调用时错的,这个问题我前面也遇到过,尝试解释过,但不知道对不对。

3.2输出矩阵

目的很明确,把矩阵输出。
没什么好办法,一个个的遍历,因为triList里面的元素是按照行来排序的,所以依次遍历,对比该位置是否存在值,存在输出,不存在输出0.

  1. template<class T>
  2. void SparseMatrix<T>::print()
  3. {
  4. int i, j, k;//中间变量
  5. //输出
  6. for(i = 1, k = 0; i <= this->row; i++)
  7. {
  8. for(j = 1; j <=this->col; j++)
  9. {
  10. int r=this->triList[k].r;
  11. int c=this->triList[k].c;
  12. if(i == r &&j == c)
  13. {
  14. cout<<this->triList[k].elem<<"\t";
  15. k++;
  16. }
  17. else cout<<0<<"\t";
  18. }
  19. cout<<endl;
  20. }
  21. }

3.3转置

这块运用的是快速转置。这边遇到的问题是,调试的时候,多次遇到错,检测不出来,到最后发现,是因为没有全部重建,导致部分语句并没有被重编译,给debug带来巨大的麻烦,切记。
代码本身还是很好理解的,书上也给了详细的说明:

  1. /*
  2. 输出
  3. */
  4. template<class T>
  5. void SparseMatrix<T>::trans(SparseMatrix<T>& B)
  6. {
  7. int co=col;
  8. B.row = this->col;
  9. B.col = this->row;
  10. B.num = this->num;
  11. B.triList.resize(num);
  12. if(num == 0)
  13. return;
  14. int* cnum = new int [100];
  15. int* cpot = new int [100];
  16. for(int i=0; i<co; i++)
  17. cnum[i] = 0;
  18. for(int t=0; t<num;t++)
  19. {
  20. // cout<<t<<endl;
  21. // cout<<triList[t].c ;
  22. ++cnum[triList[t].c];
  23. }
  24. cpot[1] = 0;
  25. for(i=2; i<=co; i++)
  26. cpot[i] = cpot[i-1]+cnum[i-1];
  27. for(int p=0; p<num; p++)
  28. {
  29. int n = triList[p].c;
  30. int q = cpot[n];
  31. B.triList[q].r = triList[p].c;
  32. B.triList[q].c = triList[p].r;
  33. B.triList[q].elem = triList[p].elem;
  34. ++cpot[n];
  35. }
  36. delete[] cnum;
  37. delete[] cpot;
  38. }

四、测试

最后,做一个小小的测试,由于无参构造函数也需要输入值,如果不真的需要值,可以输入0 0 0;

  1. int main()
  2. {
  3. SparseMatrix<int> sm(r,c,num,Load("data.txt"));
  4. sm.print();
  5. SparseMatrix<int> sm1;
  6. sm.trans(sm1);
  7. cout<<"转置后"<<endl;
  8. sm1.print();
  9. return 0;
  10. }

测试截图:
此处输入图片的描述

2015年4月22日晚

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注