导航

稀疏矩阵的抽象数据类型和一些基本操作的实现

Posted on 2015-09-28 18:53  CSU蛋李  阅读(1115)  评论(0编辑  收藏  举报

头文件:

#ifndef ADT_TSMatrix_H
#define ADT_TSMatrix_H
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define MYOVERFLOW -2
#define MAXSIZE 12500 //假设非零元素个数的最大值为12500
typedef int Status;
typedef int Elemtype;//用指定标识符Elemtype代表int类型,顾名思义表示元素类型为int型

typedef struct{
    int i, j;        //该非零元素的行下标和列下标
    Elemtype e;
}Triple;

typedef struct{
    Triple data[MAXSIZE + 1];//非零元三元组表,data[0]未用
    int mu, nu, tu;          //矩阵的行数,列数和非零元个数
}TSMatrix;

//-------------稀疏矩阵的基本操作------------

Status CreateSMatrix(TSMatrix &M);//操作结果:创建稀疏矩阵M。

Status DestroySMatrix(TSMatrix &M);//在稀疏矩阵存在的情况下,销毁稀疏矩阵M

Status PrintSMatrix(TSMatrix M);//稀疏矩阵存在的情况下,输出稀疏矩阵M

Status CopySMatrix(TSMatrix M, TSMatrix &T);//稀疏矩阵M存在,由稀疏矩阵M复制得到T

Status AddSMatrix(TSMatrix M, TSMatrix N, TSMatrix &Q);
//稀疏矩阵M与N的行数和列数对应相等,求得稀疏矩阵Q=M+N。

Status SubtMatrix(TSMatrix M, TSMatrix N, TSMatrix &Q);
//稀疏矩阵M与N的行数和列数对应相等,求得稀疏矩阵Q=M-N。

Status MultSMatrix(TSMatrix M, TSMatrix N, TSMatrix &Q);
//稀疏矩阵M的列数等于N的行数,求得稀疏矩阵Q=M*N

Status TransposeSMatrix(TSMatrix M, TSMatrix &T);
//稀疏矩阵M存在,求得稀疏矩阵M的转置矩阵T

Status FastTransposeSMatrix(TSMatrix M, TSMatrix &T);
//稀疏矩阵M存在,求得稀疏矩阵M的装置矩阵T,但这是一种效率更高的转置算法

#endif

上述操作的实现:

#include"stdafx.h"
//-------------稀疏矩阵的基本操作------------

Status CreateSMatrix(TSMatrix &M)//操作结果:创建稀疏矩阵M。
{
    cout << "please input the number of the row:";
    cin >> M.mu;
    cout << "please input the number of the column:";
    cin >> M.nu;
    cout << "please input the number of the elem which is not equal to zero:";
    cin >> M.tu;       //输入稀疏矩阵的行数、列数、非零元素数
    cout << "please input the data :" << endl;//输入矩阵的元素,一次输入行的位置,列的位置和元素的值
    for (int i1 = 1; i1 <= M.tu; ++i1){
        cin >> M.data[i1].i >> M.data[i1].j >> M.data[i1].e;
    }
    return OK;
}

Status DestroySMatrix(TSMatrix &M)//在稀疏矩阵存在的情况下,销毁稀疏矩阵M
{
    if (M.tu != 0){
        for (int ii = 1; ii <= M.tu; ++ii){
            M.data[ii].i = 0;
            M.data[ii].j = 0;
            M.data[ii].e = 0;
        }
        M.mu = 0;
        M.tu = 0;
        M.nu = 0;
        return OK;
    }
    else return ERROR;
}

Status PrintSMatrix(TSMatrix M)//稀疏矩阵存在的情况下,输出稀疏矩阵M
{
    if (M.tu == 0)return ERROR;
    else {
        cout << 'i' << "  " << "j" << "  " << "e" << endl;
        for (int ii = 1; ii <= M.tu; ++ii){
            cout << M.data[ii].i << " " << M.data[ii].j << " " << M.data[ii].e << endl;
        }
        cout << endl;
    }
    return OK;
}

Status CopySMatrix(TSMatrix M, TSMatrix &T)//稀疏矩阵M存在,由稀疏矩阵M复制得到T
{
    T.mu = M.mu;
    T.nu = M.nu;
    T.tu = M.tu;
    for (int ii = 1; ii <= M.tu; ++ii){
        T.data[ii].i = M.data[ii].i;
        T.data[ii].j = M.data[ii].j;
        T.data[ii].e = M.data[ii].e;
    }
    return OK;
}

Status AddSMatrix(TSMatrix M, TSMatrix N, TSMatrix &Q)
//稀疏矩阵M与N的行数和列数对应相等,求得稀疏矩阵Q=M+N。
{
    if (M.mu == N.mu&&M.nu == N.nu){//稀疏矩阵M和N的行数列数相等,才进行运算
        Q.mu = M.mu;                //为Q的行和列赋值
        Q.nu = M.nu;
        int M_temp = 1, N_temp = 1; //这是M和N当前的位置都为1
        int len = 1;                //这是Q的当前非零元个数
        for (; M_temp<=M.tu&&N_temp<=N.tu; ++len){ 
            if (M.data[M_temp].i < N.data[N_temp].i){//如果M的当前非零元素的行值小于N的,则直接把M的这个元素拷贝给Q
                Q.data[len].i = M.data[M_temp].i;
                Q.data[len].j = M.data[M_temp].j;
                Q.data[len].e = M.data[M_temp].e;    //M的当前位置向前走一步
                ++M_temp;
            }
            else if (M.data[M_temp].i == N.data[N_temp].i){//如果M的当前非零元素的行值等于N的,则还需比较列值
                if (M.data[M_temp].j < N.data[N_temp].j){  //如果M的列值<N的列值,这把M的这个元素拷贝给Q
                    Q.data[len].i = M.data[M_temp].i;
                    Q.data[len].j = M.data[M_temp].j;
                    Q.data[len].e = M.data[M_temp].e;
                    ++M_temp;                            //M的当前位置向前走一步
                }
                else if (M.data[M_temp].j == N.data[N_temp].j){//如果M的列值=N的列值
                    if (M.data[M_temp].e != -N.data[N_temp].e){//如果这个位置相同的两个元素之和不为零,则将相应的e值拷贝给Q
                        Q.data[len].i = M.data[M_temp].i;
                        Q.data[len].j = M.data[M_temp].j;
                        Q.data[len].e = M.data[M_temp].e + N.data[N_temp].e;
                    }
                    else --len;                               //如果和=0,则在这个循环中,Q的长度并未增加,将len减去1
                    ++N_temp;                                  //N的当前位置向前走一步
                    ++M_temp;                                  //M的当前位置向前走一步
                }
                else{                                         //如果M的列值>N的列值,把N的这个元素拷贝给Q
                    Q.data[len].i = N.data[N_temp].i;
                    Q.data[len].j = N.data[N_temp].j;
                    Q.data[len].e = N.data[N_temp].e;
                    ++N_temp;                                 //N的当前位置向前走一步
                }
            }
            else{                                             //如果M的行值>N的行值,把N的这个元素拷贝给Q
                Q.data[len].i = N.data[N_temp].i;
                Q.data[len].j = N.data[N_temp].j;
                Q.data[len].e = N.data[N_temp].e;
                ++N_temp;                                     //N的当前位置向前走一步
            }
        }
        if (M_temp > M.tu){                                //如果是M的元素先检查完,则把N的剩下的元素拷贝给Q
            for (; N_temp <= N.tu; ++N_temp, ++len){
                Q.data[len].i = N.data[M_temp].i;
                Q.data[len].j = N.data[M_temp].j;
                Q.data[len].e = N.data[M_temp].e;
            }
        }
        else{
            for (; M_temp <= M.tu; ++M_temp,++len){       //如果是N的元素先检查完,则把M的剩下的元素拷贝给Q
                Q.data[len].i = M.data[M_temp].i;
                Q.data[len].j = M.data[M_temp].j;
                Q.data[len].e = M.data[M_temp].e;
            }
        }                                                //同时检查完,则不需要其他操作
            Q.tu = --len;
            return OK;
    }
    return ERROR;
}


Status SubtMatrix(TSMatrix M, TSMatrix N, TSMatrix &Q)
//稀疏矩阵M与N的行数和列数对应相等,求得稀疏矩阵Q=M-N。
{
    for (int i = 1; i <= N.tu; ++i)         //减法只是加法的另一种形式而已,将矩阵N的全部数据元素取反,
        N.data[i].e = -N.data[i].e;         //然后按照加法的规则,进行运算
    if(AddSMatrix(M, N, Q))return OK;
    else return ERROR;
}

Status MultSMatrix(TSMatrix M, TSMatrix N, TSMatrix &Q)
//稀疏矩阵M的列数等于N的行数,求得稀疏矩阵Q=M*N
{
    if (M.nu != N.mu)return ERROR;           //如果M的列数和N的行数不相等,则矩阵无法相乘
    Q.mu = M.mu;
    Q.nu = N.nu;
    Q.tu = 0;
    int M_rpos[50] = { 0 }, N_rpos[50] = { 0 }, M_num[50] = { 0 }, N_num[50] = { 0 }, ctemp[50];
    M_rpos[1] = 1; N_rpos[1] = 1;            //M和N的第一行的第一个非零元素的位置一定是1
    for (int i = 1; i <= M.tu; ++i)          //求得M中每一行元素的个数
        ++M_num[M.data[i].i];
    for (int i = 1; i <= N.tu; ++i)          //求得N中每一行元素的个数
        ++N_num[N.data[i].i];
    for (int i = 2; i <= M.mu; ++i)          //求得M中每一行第一个非零元素的位置
        M_rpos[i] = M_rpos[i - 1] + M_num[i-1];
    for (int i = 2; i <= N.mu; ++i)          //求得N中每一行第一个非零元素的位置
        N_rpos[i] = N_rpos[i - 1] + N_num[i - 1];
    if (M.tu*N.tu != 0){                     //如果M和N中都有非零元素才进行下面的步骤
        for (int row = 1; row <= M.mu; ++row){//按照M中的行序对Q的结果进行求值
            for (int i = 1; i < 50; ++i)     //每次循环都要将这个临时累加器清零
                ctemp[i] = 0;
            int tp = 0, t = 0, ccol = 0, brow = 0;
            if (row < M.mu)tp = M_rpos[row + 1];//如果行数<M的最大行数,则每行的下一行第一个非零元素的位置为M_rpos[row+1]
            else tp = M.tu + 1;                 //最后一行的为M.tu+1
            for (int p = M_rpos[row]; p < tp; ++p){//当前行的第一个元素的位置赋予P
                brow = M.data[p].j;                //得到该元素的列数,从而对N相等的行进行运算
                if (brow < N.mu)t = N_rpos[brow + 1];//如果行数<N的最大行数,则每行的下一行第一个非零元素的位置为N_rpos[row+1]
                else t = N.tu + 1;                   //最后一行的为N.tu+1
                for (int q = N_rpos[brow]; q < t; ++q){
                     ccol = N.data[q].j;                    //将该列的结果暂时保存在ctemp[ccol]中,因为
                    ctemp[ccol] += M.data[p].e*N.data[q].e; // 只有当该行全部运算完,才知道Q的该行的第ccol列确切的值
                }
            }
            for (ccol = 1; ccol <= Q.nu;++ccol)//将结果赋予Q
            if (ctemp[ccol]){
                Q.data[++Q.tu].i = row;
                Q.data[Q.tu].j = ccol;
                Q.data[Q.tu].e = ctemp[ccol];
            }
        }
    }
    return OK;
}

Status TransposeSMatrix(TSMatrix M, TSMatrix &T)
//稀疏矩阵M存在,求得稀疏矩阵M的转置矩阵T
{
    if (M.tu > 0){
        T.mu = M.nu;
        T.nu = M.mu;
        T.tu = 1;
        for (int i = 1; i <= M.nu; ++i){
            for (int j = 1; j <= M.tu; ++j){
                if (M.data[j].j == i){
                    T.data[T.tu].i = M.data[j].j;
                    T.data[T.tu].j = M.data[j].i;
                    T.data[T.tu].e = M.data[j].e;
                    ++T.tu;
                }
            }    
        }
        --T.tu;
        return OK;
    }
    return ERROR;
}

Status FastTransposeSMatrix(TSMatrix M, TSMatrix &T)
//稀疏矩阵M存在,求得稀疏矩阵M的装置矩阵T,但这是一种效率更高的转置算法
{
    T.mu = M.nu;
    T.nu = M.mu;
    T.tu = M.tu;
    if (M.tu){
        int num[50] = { 0 };
        int cpot[50] = { 0 };
        cpot[1] = 1;
        for (int i = 1; i <= M.tu; ++i)
            ++num[M.data[i].j];
        for (int i = 2; i <= M.nu; ++i)
            cpot[i] = cpot[i - 1] + num[i - 1];
        for (int i = 1; i <= M.tu; ++i){
            int column = M.data[i].j;
            int pos = cpot[column];
            T.data[pos].i = M.data[i].j;
            T.data[pos].j = M.data[i].i;
            T.data[pos].e = M.data[i].e;
            ++cpot[column];
        }
    }
    return OK;
}

对于两种转置算法和矩阵加法的验证,主函数:

// TSMatrix.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
    TSMatrix M, T,Q,t;
    CreateSMatrix(M);
    TransposeSMatrix(M, T);
    FastTransposeSMatrix(M, t);
    PrintSMatrix(T);
    PrintSMatrix(t);
    AddSMatrix(M, T, Q);
    PrintSMatrix(Q);
    return 0;
}

结果:

对于稀疏矩阵乘法的验证,主函数:

// TSMatrix.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
    TSMatrix M, T, Q;
    CreateSMatrix(M);
    CreateSMatrix(T);
    MultSMatrix(M, T, Q);
    PrintSMatrix(Q);
    return 0;
}

结果: