稀疏矩阵中的相关问题

1.什么是稀疏矩阵?

稀疏矩阵就是矩阵中有大量零元素

2.稀疏矩阵的好处

节省空间

3.稀疏矩阵的类模板定义:

#ifndef TRIPLE_H_INCLUDED
#define TRIPLE_H_INCLUDED
template <class ElemType>
struct Triple
{
    int row,col;
    ElemType value;
    Triple()
    {
    }
    Triple(int r, int c ,ElemType v)
    {
        row=r;
        col=c;
        value=v;
    }
};

#endif // TRIPLE_H_INCLUDED

(三元组定义)

 1 #ifndef TRISPARSEMATRIX_H_INCLUDED
 2 #define TRISPARSEMATRIX_H_INCLUDED
 3 #include "Triple.h"
 4 #include "Assistance.h"//一些通用的辅助功能,和稀疏矩阵无关
 5 template <class ElemType>
 6 class TriSparseMatrix
 7 {
 8 protected:
 9     Triple<ElemType> *triElems;
10     int maxSize;
11     int rows,cols,num;
12 public:
13     TriSparseMatrix(int rs=100,int cs=100,int size=10000);
14     ~TriSparseMatrix();
15     int getRows() const;
16     int getCols() const;
17     int getNum() const;
18     Status setElem(int r,int c ,const ElemType &v);
19     Status getElem(int r,int c,ElemType &v);
20     TriSparseMatrix(const TriSparseMatrix<ElemType> &copy);
21     void simpleTranspose(TriSparseMatrix<ElemType> &b);
22     void fastTranspose(TriSparseMatrix<ElemType> &b);
23     TriSparseMatrix<ElemType> &operator =(const TriSparseMatrix<ElemType> &copy);
24 };
25
26
27 #endif // TRISPAREMATRIX_H_INCLUDED

(三元组顺序表稀疏矩阵类)

4.三元组顺序表的相关函数实现

<1>修改稀疏矩阵的函数

template <class ElemType>
Status TriSparseMatrix<ElemType>::setElem(int r,int c,const ElemType &v)
{
    if (r >= rows || c >= cols || r < 0 || c < 0)
        return RANGE_ERROR;                    // 下标范围错
        int i, j;                                // 工作变量
    for (j = num - 1; j >= 0 && (r < =triElems[j].row  && c < triElems[j].col); j--);// 查找三元组位置

    if (j >= 0 && triElems[j].row == r && triElems[j].col == c)
        {    // 找到三元组
        if (v == 0)    {    // 删除三元组
            for (i = j + 1; i < num; i++)
                triElems[i - 1] = triElems[i];    // 前移从j+1开始的三元组
            num--;                                // 删除三元组后,非零元个数自减1
        }
        else    // 修改元素值
            triElems[j].value = v;
        return SUCCESS;                        // 成功
    }
    else if (v != 0)    {
        if (num < maxSize)        {    // 将三元组(r, c, v)插入到三元组表中
            for (i = num - 1; i > j; i--)    // 后移元素
                triElems[i + 1] = triElems[i];
            // j + 1为空出的插入位置
            triElems[j + 1].row = r;        // 行
            triElems[j + 1].col = c;        // 列
            triElems[j + 1].value = v;        // 非零元素值
            num++;                            // 插入三元组后,非零元个数自加1
            return SUCCESS;                    // 成功
        }
        else    // 溢出
            return OVER_FLOW;                // 溢出时返回OVER_FLOW
    }
    return SUCCESS;
}

解释:这段代码主要的作用是改变某个三元组的值。(1)如果原来(r,c)位置存在非零元素,如果要修改v==0.那么就应该删除该三元组,因为稀疏矩阵式不存储零元素的。如果要修改的v!=0,那么直接赋值就好(2)如果原来(r,c)位置不存在并且v!=0那么就就要插入这个(r,c,v)的三元组,如果v==0那么也不用管了。理由同上。

<2>稀疏矩阵的转置函数

首先介绍简单转置方法。大致思想就是从第一列到最后一列,先找出每一列的所有三元组然后row和col互换。代码实现如下:

template <class ElemType>
void TriSparseMatrix<ElemType>::simpleTranspose(TriSparseMatrix<ElemType> &b)
{
    b.rows=cols;
    b.cols=rows;
    b.num=num;
    b.maxSize=maxSize;
    if(b.triElems!=NULL)
        delete [] b.triElems;
    b.triElems=new Triple<ElemType>[b.maxSize];
    if(b.num>0)
    {
        int i=0;
        for(int col=0;col<cols;col++)
        {
            for(int j=0;j<num;j++)
            {
                if(triElems[j].col==col)
                {
                    b.triElems[i].row=triElems[j].col;
                    b.triElems[i].col=triElems[j].row;
                    b.triElems[i].value=triElems[j].value;
                    i++;
                }
            }
        }
    }
}

(简单转置)

上述的算法时间复杂度是O(rows*cols)

下面介绍快速转置:

首先算出来每一列的非零元素(cNum),然后根据cNum算出来转置后的矩阵的存储位置。大致思想就是这样,下面的是代码实现

template <class ElemType>
void TriSparseMatrix<ElemType>::fastTranspose(TriSparseMatrix<ElemType> &b)
{
    b.rows=cols;
    b.cols=rows;
    b.num=num;
    b.maxSize=maxSize;
    delete [] b.triElems;
    b.triElems=new Triple<ElemType>[b.maxSize];
    int *cNum=new int [cols+1];// 存放原矩阵中每一列的非零元个数
    int *cPos=new int [cols+1];// 存放原矩阵中每一列的第一个非零元在b中的存储位置
    int col,i;
    if(b.num>0)
    {
        for (col=0;col<cols;col++)
        {
            cNum[col]=0;//初始化cNum
        }
        for(i=0;i<num;i++)// 统计原矩阵中每一列的非零元个数
            ++cNum[triElems[i].col];
        cPos[0]=0;// 第一列的第一个非零元在b存储的起始位置
        for(col=1;col<cols;col++)// 循环求每一列的第一个非零元在b存储的起始位置
            cPos[col]=cPos[col-1]+cNum[col-1];
        for(i=0;i<num;i++)
        {
            int j=cPos[triElems[i].col];//用于表示b当前列的下一个非零元素位置
            b.triElems[j].row=triElems[i].col;
            b.triElems[j].col=triElems[i].row;
            b.triElems[j].value=triElems[i].value;
            ++cPos[triElems[i].col];
        }
    }
    delete [] cNum;
    delete [] cPos;
}

(快速转置)

以下面的矩阵为例说明一下快速转置的流程

15, 0, 0, 22, 0, -5,
0, 11, 3, 0, 0, 0,
0, 0, 0, 6, 0, 0,
0, 0, 0, 0, 0, 0,
91, 0, 0, 0, 0, 0,
0, 7, 0, 0, 0, 0,
0, 0, 28, 0, 0, 0
可以求出CNum={2,2,2,2,0,1},原始矩阵的第一列的第一个非零元素在转置矩阵的位置肯定是row=0,col=0;也就是triElemd[0],第一列的下面的元素一次递增。如果到第二列的话,那么第二列的第一个非零元素的位置应该是第一列的第一个非零元素在转置矩阵的位置(第一列的第一元素在转置矩阵的位置是triElem[0])加上第一列的非零元素的总数teiElem[2]。一次类推,原矩阵第三列的第一个非零元素在倒置矩阵的位置是原矩阵中第二列第一个非零元素在倒置矩阵的位置加上第二列的非零元素的个数也就是teiElem[4]。

下面贴下完整的代码

  1 #include "TriSparseMatrix.h"
  2 #include  "Triple.h"
  3 #include "Assistance.h"
  4 #include <iostream>
  5 using namespace std;
  6 template <class ElemType>
  7 TriSparseMatrix<ElemType>::TriSparseMatrix(int rs,int cs,int size)
  8 {
  9     if(rs<1||cs<1)
 10         throw Error("行数或者列数无效!");
 11     maxSize=size;
 12     num=0;
 13     rows=rs;
 14     cols=cs;
 15     triElems=new Triple<ElemType>[maxSize];
 16 }
 17 template <class ElemType>
 18 TriSparseMatrix<ElemType>::TriSparseMatrix(const TriSparseMatrix<ElemType> &copy)
 19 // 操作结果:由稀疏矩阵copy构造新稀疏矩阵——复制构造函数
 20 {
 21     maxSize = copy.maxSize;                            // 最大非零元素个数
 22     triElems = new Triple<ElemType>[maxSize];        // 分配存储空间
 23     rows = copy.rows;                                // 复制行数
 24     cols = copy.cols;                                // 复制列数
 25     num = copy.num;                                    // 复制非零元素个数
 26     triElems = new Triple<ElemType>[maxSize];        // 为三元组分配存储空间
 27     for (int i = 0; i < num; i++)    // 复制三元组
 28         triElems[i] = copy.triElems[i];
 29 }
 30
 31 template <class ElemType>
 32 TriSparseMatrix<ElemType>::~TriSparseMatrix()
 33 {
 34     if(triElems!=NULL)
 35         delete [] triElems;
 36 }
 37 template <class ElemType>
 38 int TriSparseMatrix<ElemType>::getRows() const
 39 {
 40     return rows;
 41 }
 42 template <class ElemType>
 43 int TriSparseMatrix<ElemType>::getCols() const
 44 {
 45    return cols;
 46 }
 47 template <class ElemType>
 48 int TriSparseMatrix<ElemType>::getNum() const
 49 {
 50    return num;
 51 }
 52 template <class ElemType>
 53 Status TriSparseMatrix<ElemType>::setElem(int r,int c,const ElemType &v)
 54 {
 55     if (r >= rows || c >= cols || r < 0 || c < 0)
 56         return RANGE_ERROR;                    // 下标范围错
 57         int i, j;                                // 工作变量
 58     for (j = num - 1; j >= 0 && (r < =triElems[j].row  && c < triElems[j].col); j--);// 查找三元组位置
 59
 60     if (j >= 0 && triElems[j].row == r && triElems[j].col == c)
 61         {    // 找到三元组
 62         if (v == 0)    {    // 删除三元组
 63             for (i = j + 1; i < num; i++)
 64                 triElems[i - 1] = triElems[i];    // 前移从j+1开始的三元组
 65             num--;                                // 删除三元组后,非零元个数自减1
 66         }
 67         else    // 修改元素值
 68             triElems[j].value = v;
 69         return SUCCESS;                        // 成功
 70     }
 71     else if (v != 0)    {
 72         if (num < maxSize)        {    // 将三元组(r, c, v)插入到三元组表中
 73             for (i = num - 1; i > j; i--)    // 后移元素
 74                 triElems[i + 1] = triElems[i];
 75             // j + 1为空出的插入位置
 76             triElems[j + 1].row = r;        // 行
 77             triElems[j + 1].col = c;        // 列
 78             triElems[j + 1].value = v;        // 非零元素值
 79             num++;                            // 插入三元组后,非零元个数自加1
 80             return SUCCESS;                    // 成功
 81         }
 82         else    // 溢出
 83             return OVER_FLOW;                // 溢出时返回OVER_FLOW
 84     }
 85     return SUCCESS;
 86 }
 87 template <class ElemType>
 88 Status TriSparseMatrix<ElemType>::getElem(int r, int c, ElemType &v)
 89 {
 90     if(r>=rows||c>=cols||r<0||c<0)
 91     {
 92         return RANGE_ERROR;
 93     }
 94     int j;
 95     for(j=num-1;j>=0&&(r<triElems[j].row||r==triElems[j].row&&c<triElems[j].col);j--);//查找制定三元组的位置
 96     if(j>=0&&triElems[j].row==r&&triElems[j].col==c)
 97     {
 98         v=triElems[j].value;
 99     }
100     else
101     {
102         v=0;
103     }
104     return SUCCESS;
105 }
106
107 template <class ElemType>
108 TriSparseMatrix<ElemType> &TriSparseMatrix<ElemType>::operator =(const TriSparseMatrix<ElemType> &copy)
109 {
110     if(&copy!=this)
111     {
112         maxSize=copy.maxSize;
113         if(triElems!=NULL)
114             delete [] triElems;
115         triElems=new Triple<ElemType>[maxSize];
116         rows=copy.rows;
117         cols=copy.cols;
118         num=copy.num;
119         for(int i=0;i<num;i++)
120         {
121             triElems[i]=copy.triElems[i];
122         }
123     }
124     return *this;
125
126 }
127 /*
128 *简单转置,大致思路先找出一列的所用元素,row和col互换
129 */
130 template <class ElemType>
131 void TriSparseMatrix<ElemType>::simpleTranspose(TriSparseMatrix<ElemType> &b)
132 {
133     b.rows=cols;
134     b.cols=rows;
135     b.num=num;
136     b.maxSize=maxSize;
137     if(b.triElems!=NULL)
138         delete [] b.triElems;
139     b.triElems=new Triple<ElemType>[b.maxSize];
140     if(b.num>0)
141     {
142         int i=0;
143         for(int col=0;col<cols;col++)
144         {
145             for(int j=0;j<num;j++)
146             {
147                 if(triElems[j].col==col)
148                 {
149                     b.triElems[i].row=triElems[j].col;
150                     b.triElems[i].col=triElems[j].row;
151                     b.triElems[i].value=triElems[j].value;
152                     i++;
153                 }
154             }
155         }
156     }
157 }
158
159 template <class ElemType>
160 void TriSparseMatrix<ElemType>::fastTranspose(TriSparseMatrix<ElemType> &b)
161 {
162     b.rows=cols;
163     b.cols=rows;
164     b.num=num;
165     b.maxSize=maxSize;
166     delete [] b.triElems;
167     b.triElems=new Triple<ElemType>[b.maxSize];
168     int *cNum=new int [cols+1];// 存放原矩阵中每一列的非零元个数
169     int *cPos=new int [cols+1];// 存放原矩阵中每一列的第一个非零元在b中的存储位置
170     int col,i;
171     if(b.num>0)
172     {
173         for (col=0;col<cols;col++)
174         {
175             cNum[col]=0;//初始化cNum
176         }
177         for(i=0;i<num;i++)// 统计原矩阵中每一列的非零元个数
178             ++cNum[triElems[i].col];
179         cPos[0]=0;// 第一列的第一个非零元在b存储的起始位置
180         for(col=1;col<cols;col++)// 循环求每一列的第一个非零元在b存储的起始位置
181             cPos[col]=cPos[col-1]+cNum[col-1];
182         for(i=0;i<num;i++)
183         {
184             int j=cPos[triElems[i].col];//用于表示b当前列的下一个非零元素位置
185             b.triElems[j].row=triElems[i].col;
186             b.triElems[j].col=triElems[i].row;
187             b.triElems[j].value=triElems[i].value;
188             ++cPos[triElems[i].col];
189         }
190     }
191     delete [] cNum;
192     delete [] cPos;
193 }

(完整的模板类实现)

上课的时候我也是想了很久,才理解,所以写了下来。写的不好请大家见谅!还有代码呢,很大和老师给的代码几乎都一样,我是一句句敲下来的,看见相同的代码不要见怪!

时间: 2024-08-18 05:31:24

稀疏矩阵中的相关问题的相关文章

C语言中随机数相关问题

用C语言产生随机数重要用到rand函数.srand函数.及宏RAND_MAX(32767),它们均在stdlib.h中进行了声明. int rand(void);//生成一个随机数 voidsrand(unsigned int seed); //为rand设置"种子"的值 srand()就是给rand()提供种子seed,如果srand每次输入的数值是一样的,那么每次运行产生的随机数也是一样的.通常的做法是以这样一句代码: srand((unsigned)time(NULL)); 来取

补充:sql server 中的相关查询、case函数

相关查询(在同一个表中) 相关查询类似子查询,但是又不同于子查询:子查询中的子条件可以单独查出数据,但是相关查询的子条件不能查处数据.(可以理解成C#中for的穷举法,第一个for走一个,第二个for走一圈,在相关查询中,括号内的数据只有几个,外面的查询有全部的数据,每个数据到括号中去比较是否合适) 格式: select * from 表名1 as a where a.列名 关系表达式或逻辑运算符 ( select * from 表名1 as b where a.相关列名1 = b.相关列名1

理解CSV文件以及ABAP中的相关操作

在很多ABAP开发中,我们使用CSV文件,有时候,关于CSV文件本身的一些问题使人迷惑.它仅仅是一种被逗号分割的文本文档吗? 让我们先来看看接下来可能要处理的几个相关组件的词汇的语义. Separator:两个字段之间的界线,在CSV文件中即是“,”. Delimiter:这种符号的开端和结束,代表了某种东西的界限.举个例子“测试字符串”有两个delimiters,即两个双引号.在很多逗号需要成为文本的情况下,这些CSV文件会使用双引号作为Delimiter. Terminator : 代表片段

(笔记)Linux内核中内存相关的操作函数

linux内核中内存相关的操作函数 1.kmalloc()/kfree() static __always_inline void *kmalloc(size_t size, gfp_t flags) 内核空间申请指定大小的内存区域,返回内核空间虚拟地址.在函数实现中,如果申请的内存空间较大的话,会从buddy系统申请若干内存页面,如果申请的内存空间大小较小的话,会从slab系统中申请内存空间.有关buddy和slab,请参见<linux内核之内存管理.doc> gfp_t flags 的选项

HTML中CSS相关选择器

1.选择器的分类: 1 h1,h2,h3,h4 { 2 color:red; 3 } 2.派生选择器: 1 li strong{ 2 color:red; 3 } 3.id选择器: 1 1 #red{ 2 color:red; 3 } 4 #green{ 5 color:green; 6 } 8 9 HTML: 10 <p id="red">I am red</p> 11 <p id="green">I am green</

Java中Map相关的快速查找算法与唯一性(转载)

原文地址:http://blog.csdn.net/chuyuqing/article/details/19629229 在对<Set和hashCode()>的一篇原创文章写完后,由于对自己的一些论断产生了模糊和怀疑,因此又对Set进行了一些研究,形成本篇. 在Set的使用场景中,我们不外乎看中了她存储数据的唯一性,即不能存储重复值,这在某些应用场合下是很必要的一个特性.那么从更深一层来考虑,Set究竟如何使数据不重复的呢?从另一个层面来考虑,她又如何确保在验证数据是否重复过程中的快速性呢?假

原生 JS 中对象相关 API 合集

https://juejin.im/entry/58f8a705a0bb9f0065a4cb20 原文链接:https://microzz.com/2017/04/20/jsobject/ 原生 JavaScript 中对象相关 API 合集 - 对象篇.现在 jQuery 已经没有那么有优势了,原生 JS 赶紧学起来... -- 由microzz分享 Microzz [email protected] 主页 文章 标签 GitHub 关于我 掘金专栏 SegmentFault Vue音乐播放器

【Socket编程】Java中网络相关API的应用

Java中网络相关API的应用 一.InetAddress类 InetAddress类用于标识网络上的硬件资源,表示互联网协议(IP)地址. InetAddress类没有构造方法,所以不能直接new出一个对象: InetAddress类可以通过InetAddress类的静态方法获得InetAddress的对象: 1 InetAddress.getLocalHost();//获取本地对象 2 InetAddress.getByName("");//获取指定名称对象 主要方法使用: 1 /

c语言中条件编译相关的预编译指令

一. 内容概述 本文主要介绍c语言中条件编译相关的预编译指令,包括#define.#undef.#ifdef.#ifndef.#if.#elif.#else.#endif.defined. 二.条件编译 条件编译是根据实际定义宏(某类条件)进行代码静态编译的手段.可根据表达式的值或某个特定宏是否被定义来确定编译条件. 最常见的条件编译是防止重复包含头文件的宏,形式跟下面代码类似: 1 #ifndef ABCD_H 2 #define ABCD_H 3 4 // ... some declarat