《数据结构、算法与应用C++语言描述》使用C++语言实现二维数组稀疏矩阵

《数据结构、算法与应用C++语言描述》使用C++语言实现二维数组稀疏矩阵

稀疏矩阵定义

一个mxn 的矩阵,如果大多数元素都是0,则称为稀疏矩阵(spare matrix)。一个矩阵如果不是稀疏的,就称为稠密矩阵(dense matrix)。在稀疏矩阵和稠密矩阵之间没有明确的界限。nxn的对角矩阵和三对角矩阵是稀疏矩阵。它们的非0元素是 O ( n ) O(n) On,0元素是 O ( n 2 O(n^2 On2)。

本节规定,稀疏矩阵的非0元素个数要小于 n 2 / 3 n^2/3 n2/3,有时还要小于 n 2 / 5 n^2/5 n2/5,因此三角矩阵被视为稠密矩阵。

代码实现

_12matrixTerm.h

稀疏矩阵的单个节点结构。

/*
Project name :			allAlgorithmsTest
Last modified Date:		2022年8月13日17点38分
Last Version:			V1.0
Descriptions:			用于存储稀疏矩阵的行号、列号和元素的结构体
*/

#ifndef _MATRIXTERM_H_
#define _MATRIXTERM_H_
using namespace std;
template <class T>
struct matrixTerm 
{
   int row,     
       col;
   T value;

   operator T() const {return value;}
      // type conversion from matrixTerm to T
};

#endif

_13sparseMatrix.h

模板类

/*
Project name :			allAlgorithmsTest
Last modified Date:		2023年9月19日21点59分
Last Version:			V1.0
Descriptions:			数组线性表存储的稀疏矩阵类头文件
*/
#pragma once
//稀疏矩阵的类
#ifndef _SPARSEMATRIX_H_
#define _SPARSEMATRIX_H_

#include 
#include "_12matrixTerm.h"
#include 
#include "_1myExceptions.h"
using std::ostream;
using std::istream;
using std::cout;
using std::cin;
using std::vector;
using std::endl;
void sparseMatrixTest();//测试函数
/*行主描述的稀疏矩阵*/
template<class T>
class sparseMatrix
{
public:
    void transpose(sparseMatrix<T>& b);
    void add(sparseMatrix<T>& b, sparseMatrix<T>& c);
    friend ostream& operator<< <T>(ostream& out, sparseMatrix<T>& x);
    friend istream& operator>> <T>(istream& in, sparseMatrix<T>& x);
private:
    int rows;   // number of rows in matrix
    int cols;    // number of columns in matrix
    vector<matrixTerm<T>> terms;
    // list of nonzero terms
};
// overload <<
template <class T>
ostream& operator<<(ostream& out, sparseMatrix<T>& x)
{
    // Put x in output stream.
    // put matrix characteristics
    out << "rows = " << x.rows << " columns = " << x.cols << endl;
    out << "nonzero terms = " << x.terms.size() << endl;
    // put terms, one per line
    for (typename vector<matrixTerm<T>>::iterator i = x.terms.begin();i != x.terms.end(); i++)
        out << "a(" << (*i).row << ',' << (*i).col << ") = " << (*i).value << endl;
    return out;
}

// overload >>
template<class T>
istream& operator>> (istream& in, sparseMatrix<T>& x)
{
    // Input a sparse matrix.
    // input matrix characteristics
    int numberOfTerms;
    cout << "Enter number of rows, columns, and #terms" << endl;    
    while (!(in >> x.rows >> x.cols >> numberOfTerms)) {//如果输入类型不匹配,则执行循环体
        in.clear(); // reset input设置标志位为有效
        while (in.get() != '\n') //删除没有用的输入
            continue; // get rid of bad input
        cout << "Enter number of rows, columns, and #terms" << endl;
    }
    //设置x.terms的大小,确保足够的容量
    x.terms.resize(numberOfTerms);
    int before_rows = 0, before_columns = 0;
    // input terms
    matrixTerm<T> mTerm;
    for (int i = 0; i < numberOfTerms; i++)
    {
        cout << "Enter row, column, and value of term " << (i + 1) << endl;
        while (!(in >> mTerm.row >> mTerm.col >> mTerm.value)) {//如果输入类型不匹配,则执行循环体
            in.clear(); // reset input设置标志位为有效
            while (in.get() != '\n') //删除没有用的输入
                continue; // get rid of bad input
            cout << "Enter row, column, and value of term " << (i + 1) << endl;
        }
        // 当前元素的位置比之前元素的位置要小
        // 行主索引 > 列主索引
        while (before_rows * x.cols + before_columns > mTerm.row * x.rows + mTerm.col)
        {
            cout << "Please enter in row master mapping order:" << endl;
            cout << "Enter row, column, and value of term " << (i + 1) << endl;
            while (!(in >> mTerm.row >> mTerm.col >> mTerm.value)) {//如果输入类型不匹配,则执行循环体
                in.clear(); // reset input设置标志位为有效
                while (in.get() != '\n') //删除没有用的输入
                    continue; // get rid of bad input
                cout << "Enter row, column, and value of term " << (i + 1) << endl;
            }
        }
        x.terms[i] = mTerm;
        before_rows = mTerm.row;
        before_columns = mTerm.col;
    }
    return in;
}
/*转置:b矩阵存储*this转置的结果*/
/*首先计算*this每一列有多少个非零元素;然后计算*this每一列首个元素的位置;最后复制元素到矩阵b*/
template<class T>
void sparseMatrix<T>::transpose(sparseMatrix<T>& b)
{
    //设置b的行长和列长,以及非零元素的数目
    b.cols = rows;
    b.rows = cols;
    b.terms.resize(terms.size());

    //colSize[i]是矩阵*this在第i列的非0元素个数
    int* colSize = new int[cols + 1];
    //rowNext[i]是转置矩阵b第i行首个非0元素在b中的索引
    int* rowNext = new int[cols + 1];
    //colSize[0]没用
    for (int i = 1; i <= cols; i++)
        colSize[i] = 0;//初始化所有colSize[i]为0
    for (typename vector<matrixTerm<T> >::iterator i = terms.begin(); i != terms.end(); i++)
        colSize[(*i).col]++;//计算矩阵*this在第i列的非0元素个数并存储到colSize中
    //rowNext[0]也没用
    rowNext[1] = 0;
    for (int i = 2; i <= cols; i++)
        rowNext[i] = rowNext[i - 1] + colSize[i - 1];

    matrixTerm<T> mTerm;
    for (typename vector<matrixTerm<T> >::iterator i = terms.begin(); i != terms.end(); i++)
    {
        int j = rowNext[(*i).col]++; // position in b
        mTerm.row = (*i).col;
        mTerm.col = (*i).row;
        mTerm.value = (*i).value;
        b.terms[j] = mTerm;// 2023年9月19日
    }
}
/*c = *this+b;通过从左至右扫描*this和b的非0项来实现的*/
template<class T>
void sparseMatrix<T>::add(sparseMatrix<T>& b, sparseMatrix<T>& c)
{
    //当矩阵*this和矩阵b的大小不匹配时,不可执行加操作
    if (rows != b.rows || cols != b.cols)
        throw matrixSizeMismatch();

    //设置矩阵c的参数
    c.rows = rows;
    c.cols = cols;
    c.terms.clear();//清空矩阵c
    int cSize = 0;

    //为*this和b定义迭代器
    typename vector<matrixTerm<T> >::iterator it = terms.begin();
    typename vector<matrixTerm<T> >::iterator ib = b.terms.begin();
    typename vector<matrixTerm<T> >::iterator itEnd = terms.end();
    typename vector<matrixTerm<T> >::iterator ibEnd = b.terms.end();

    //遍历*this和b,把相关的项相加
    while (it != itEnd && ib != ibEnd)
    {
        //计算行主索引,方便进行比较谁在前谁在后
        int tIndex = (*it).row * cols + (*it).col;
        int bIndex = (*ib).row * cols + (*ib).col;

        if (tIndex < bIndex)
        {//b的元素在后
            c.terms.insert(terms.begin() + cSize, *it);
            cSize++;
            it++;
        }
        else {
            if (tIndex == bIndex)
            {//*this和b的元素在同一位置

               //当且仅当两者相加不为0时才加入c
                if ((*it).value + (*ib).value != 0)
                {
                    matrixTerm<T> mTerm;
                    mTerm.row = (*it).row;
                    mTerm.col = (*it).col;
                    mTerm.value = (*it).value + (*ib).value;
                    c.terms.insert(terms.begin() + cSize, mTerm);
                    cSize++;
                }

                it++;
                ib++;
            }
            else
            {//a在后
                c.terms.insert(terms.begin() + cSize, *ib);
                cSize++;
                ib++;
            }
        }
    }
    //复制剩余项
    for (; it != itEnd; it++)
    {
        c.terms.insert(terms.begin() + cSize, *it);
        cSize++;
    }
        
    for (; ib != ibEnd; ib++)
    {
        c.terms.insert(terms.begin() + cSize, *ib);
        cSize++;
    }
}

#endif

_13sparseMatrix.cpp

/*
Project name :			allAlgorithmsTest
Last modified Date:		2022年8月13日17点38分
Last Version:			V1.0
Descriptions:			测试_13sparseMatrix.h头文件中的所有函数(稀疏矩阵)
*/
// test array based sparse matrix class

#include 
#include "_13sparseMatrix.h"
using namespace std;

void sparseMatrixTest()
{
	cout << endl << "********************************sparseMatrixTest()函数开始************************************" << endl;
	sparseMatrix<int> a, b, c;

	// test input and output
	cin >> a;
	cout << "Matrix a is" << endl << a;
	cin >> b;
	cout << "Matrix b is" << endl << b;

	// test transpose
	a.transpose(c);
	cout << "The transpose of a is" << endl << c;

	// test add
	a.add(b,c);
	cout << "The sum of a and b is" << endl << c;
	cout << "********************************sparseMatrixTest()函数结束************************************" << endl;
}

_1main.cpp

主函数

/*
Project name :			allAlgorithmsTest
Last modified Date:		2022年8月13日17点38分
Last Version:			V1.0
Descriptions:			main()函数,控制运行所有的测试函数
*/
#include 
#include "_13sparseMatrix.h"


int main()
{
	sparseMatrixTest();
	return 0;
}

_1myExceptions.h

异常类汇总

/*
Project name :			allAlgorithmsTest
Last modified Date:		2022年8月13日17点38分
Last Version:			V1.0
Descriptions:			综合各种异常
*/
#pragma once
#ifndef _MYEXCEPTIONS_H_
#define _MYEXCEPTIONS_H_
#include 
#include

using namespace std;

// illegal parameter value
class illegalParameterValue 
{
   public:
      illegalParameterValue(string theMessage = "Illegal parameter value")
            {message = theMessage;}
      void outputMessage() {cout << message << endl;}
   private:
      string message;
};

// illegal input data
class illegalInputData 
{
   public:
      illegalInputData(string theMessage = "Illegal data input")
            {message = theMessage;}
      void outputMessage() {cout << message << endl;}
   private:
      string message;
};

// illegal index
class illegalIndex 
{
   public:
      illegalIndex(string theMessage = "Illegal index")
            {message = theMessage;}
      void outputMessage() {cout << message << endl;}
   private:
      string message;
};

// matrix index out of bounds
class matrixIndexOutOfBounds 
{
   public:
      matrixIndexOutOfBounds
            (string theMessage = "Matrix index out of bounds")
            {message = theMessage;}
      void outputMessage() {cout << message << endl;}
   private:
      string message;
};

// matrix size mismatch
class matrixSizeMismatch 
{
   public:
      matrixSizeMismatch(string theMessage = 
                   "The size of the two matrics doesn't match")
            {message = theMessage;}
      void outputMessage() {cout << message << endl;}
   private:
      string message;
};

// stack is empty
class stackEmpty
{
   public:
      stackEmpty(string theMessage = 
                   "Invalid operation on empty stack")
            {message = theMessage;}
      void outputMessage() {cout << message << endl;}
   private:
      string message;
};

// queue is empty
class queueEmpty
{
   public:
      queueEmpty(string theMessage = 
                   "Invalid operation on empty queue")
            {message = theMessage;}
      void outputMessage() {cout << message << endl;}
   private:
      string message;
};

// hash table is full
class hashTableFull
{
   public:
      hashTableFull(string theMessage = 
                   "The hash table is full")
            {message = theMessage;}
      void outputMessage() {cout << message << endl;}
   private:
      string message;
};

// edge weight undefined
class undefinedEdgeWeight
{
   public:
      undefinedEdgeWeight(string theMessage = 
                   "No edge weights defined")
            {message = theMessage;}
      void outputMessage() {cout << message << endl;}
   private:
      string message;
};

// method undefined
class undefinedMethod
{
   public:
      undefinedMethod(string theMessage = 
                   "This method is undefined")
            {message = theMessage;}
      void outputMessage() {cout << message << endl;}
   private:
      string message;
};
#endif

你可能感兴趣的:(数据结构,算法与应用,C++语言描述学习笔记,c++,算法,数据结构)