首页 > 代码库 > 矩阵压缩存储之三元组顺序表

矩阵压缩存储之三元组顺序表

形态:


实现:

/*****************************************
稀疏矩阵的三元组顺序表存储表示
by Rowandjj
2014/5/3
******************************************/
#include<IOSTREAM>
using namespace std;

#define MAXSIZE 12500//非零元个数的最大值
typedef int ElemType;
typedef struct _DATA_
{
    int i;//行下标
    int j;//列下标
    ElemType e;//元素值
}Data,*pData;
typedef struct _MATRIX_
{    
    Data data[MAXSIZE+1];//非零元三元组表,data[0]不用
    int mu,nu,tu;//行数,列数,非零元个数
}Matrix,*pMatrix;


bool CreateMatrix(pMatrix pMatrixTemp);//创建稀疏矩阵M
bool ClearMatrix(pMatrix pMatrixTemp);//销毁稀疏矩阵
bool AddMatrix(pMatrix pMatrixTemp3,Matrix MatrixTemp1,Matrix MatrixTemp2);//矩阵求和
bool SubMatrix(pMatrix pMatrixTemp3,Matrix MatrixTemp1,Matrix MatrixTemp2);//矩阵减运算
bool MulMatrix(pMatrix pMatrixTemp3,Matrix MatrixTemp1,Matrix MatrixTemp2);//矩阵乘运算
void Convert(pMatrix pMatrixTemp3,Matrix MatrixTemp);//矩阵转置
void FastConvert(pMatrix pMatrixTemp3,Matrix MatrixTemp);//快速转置

void printMatrix(pMatrix pMatrixTemp);

int comp(int a,int b);
//-------------------------------------------
bool CreateMatrix(pMatrix pMatrixTemp)
{
    printf("请输入矩阵行数,列数,非零元个数:\n");
    scanf("%d",&pMatrixTemp->mu);
    scanf("%d",&pMatrixTemp->nu);
    scanf("%d",&pMatrixTemp->tu);
    
    pMatrixTemp->data[0].i = 0;
    int i;
    int m,n;//行,列
    ElemType e;//数据
    bool bOk = false;
    for(i = 1; i <= pMatrixTemp->tu;i++)
    {
        do 
        {
            bOk = false;
            printf("请按行序顺序输入第%d个非零元素所在的行(1~%d),列(1~%d),元素值:\n",i,pMatrixTemp->mu,pMatrixTemp->nu);
            scanf("%d",&m);
            scanf("%d",&n);
            scanf("%d",&e);
            if(m<1 || m>pMatrixTemp->mu || n<1 || n>pMatrixTemp->nu)//超出范围
            {    
                bOk = true;
            }
            //行或列的顺序有错,要求后一个元素的行列值大于前一个元素
            if(m<pMatrixTemp->data[i-1].i || m==pMatrixTemp->data[i-1].i && n<=pMatrixTemp->data[i-1].j)
            {
                bOk = true;
            }
        } while (bOk);
        //给三元组赋值
        pMatrixTemp->data[i].e = e;
        pMatrixTemp->data[i].i = m;
        pMatrixTemp->data[i].j = n;
    }
    return true;
}
bool ClearMatrix(pMatrix pMatrixTemp)
{
    pMatrixTemp->mu = 0;
    pMatrixTemp->nu = 0;
    pMatrixTemp->tu = 0;
    return true;
}
bool AddMatrix(pMatrix pMatrixTemp3,Matrix MatrixTemp1,Matrix MatrixTemp2)
{
    //1.只有两个矩阵的行和列相等时才能相加
    if(MatrixTemp1.mu != MatrixTemp2.mu)
    {
        return false;
    }
    if(MatrixTemp1.nu != MatrixTemp2.nu)
    {
        return false;
    }
    //2.初始化和矩阵的行值和列值
    pMatrixTemp3->mu = MatrixTemp1.mu;
    pMatrixTemp3->nu = MatrixTemp1.nu;
    //3.初始化指针,为每个矩阵添加头指针和尾指针
    pData pStart1 = &MatrixTemp1.data[1];
    pData pEnd1 = &MatrixTemp1.data[MatrixTemp1.tu];

    pData pStart2 = &MatrixTemp2.data[1];
    pData pEnd2 = &MatrixTemp2.data[MatrixTemp2.tu];
    //和矩阵的头尾指针默认都指向非零元素首地址的前一位(0位未存储)
    pData pStart3 = pMatrixTemp3->data;
    pData pEnd3 = pMatrixTemp3->data;
    
    //4.开始合并矩阵
    while(pStart1<=pEnd1 && pStart2<=pEnd2)
    {
        pEnd3++;
        switch(comp(pStart1->i,pStart2->i))
        {
        case 1:
            *pEnd3 = *pStart1; 
            pStart1++;
            break;
        case 0:
            switch(comp(pStart1->j,pStart2->j))
            {
            case 1:
                *pEnd3 = *pStart1;
                pStart1++;
                break;
            case 0:
                *pEnd3 = *pStart1;
                pEnd3->e += pStart2->e;
                if(pEnd3->e==0)//结果为0的元素不需要存储到稀疏矩阵中
                {
                    pEnd3--;
                }
                pStart1++;
                pStart2++;
                break;
            case -1:
                *pEnd3 = *pStart2;
                pStart2++;
                break;
            }
            break;
        case -1:
            *pEnd3 = *pStart2;
            pStart2++;
            break;
        }
    }
    //剩余部分直接放到和矩阵
    while (pStart1<=pEnd1)
    {
        pEnd3++;
        *pEnd3 = *pStart1;
        pStart1++;
    }
    while (pStart2<=pEnd2)
    {
        pEnd3++;
        *pEnd3 = *pStart2;
        pStart2++;
    }
    //非零元个数
    pMatrixTemp3->tu = pEnd3-pStart3;
    return true;
}
//a[n][m] * b[m][p] = a[n][p]
bool MulMatrix(pMatrix pMatrixTemp3,Matrix MatrixTemp1,Matrix MatrixTemp2)
{    
    //1.矩阵1的列必须和矩阵2的行相等
    if(MatrixTemp1.nu != MatrixTemp2.mu)
    {
        return false;
    }
    //2.新矩阵的行为矩阵1的行,新矩阵的列为矩阵2的列
    pMatrixTemp3->mu = MatrixTemp1.mu;
    pMatrixTemp3->nu = MatrixTemp2.nu;
    //3.动态申请临时数组存储新矩阵的元素值
    ElemType *pBase = (ElemType*)malloc(sizeof(ElemType) * (pMatrixTemp3->mu*pMatrixTemp3->nu));
    if(!pBase)
    {
        return false;
    }

    int i,j;
    int l = MatrixTemp2.nu;//矩阵2的列值,也就是新矩阵的列值
    //给数组赋初值 memset也行
    for(i = 0 ; i < pMatrixTemp3->mu*pMatrixTemp3->nu; i++)
    {
        *(pBase+i) = 0;
    }

    //4.将矩阵相乘后的值暂时存储到申请的一维数组中
    for(i = 1; i <= MatrixTemp1.tu;i++)
    {
        for(j = 1; j <= MatrixTemp2.tu;j++)
        {
           /**
            *矩阵相乘的规律,矩阵1的列值等于矩阵2的行值时才相乘
            **/
            if(MatrixTemp1.data[i].j == MatrixTemp2.data[j].i)
            {
                //存储到一维数组中
                *(pBase + (MatrixTemp1.data[i].i-1)*l+MatrixTemp2.data[j].j-1) += MatrixTemp1.data[i].e*MatrixTemp2.data[j].e;
            }
        }
    }
    //5.将一维数组的元素放回新矩阵中
    int t = 0;
    for(i = 1; i <= MatrixTemp1.mu; i++)
    {
        for(j = 1; j <= MatrixTemp2.nu;j++)
        {
            t++;
            pMatrixTemp3->data[t].e = *(pBase+(i-1)*l+j-1);
            pMatrixTemp3->data[t].i = i;
            pMatrixTemp3->data[t].j = j;
        }
    }
    //6.释放一维数组
    free(pBase);
    pMatrixTemp3->tu = t;
    return true;
}
bool SubMatrix(pMatrix pMatrixTemp3,Matrix MatrixTemp1,Matrix MatrixTemp2)
{
    for(int i = 1; i <= MatrixTemp2.tu;i++)
    {
        MatrixTemp2.data[i].e *= -1;        
    }
    AddMatrix(pMatrixTemp3,MatrixTemp1,MatrixTemp2);
    return true;
}
void Convert(pMatrix pMatrixTemp3,Matrix MatrixTemp)
{
    //适用条件 tu远小于mu*nu,否则时间复杂度将会很高
    pMatrixTemp3->mu = MatrixTemp.nu;
    pMatrixTemp3->nu = MatrixTemp.mu;
    pMatrixTemp3->tu = MatrixTemp.tu;
    int q = 1;
    for(int i = 1; i <= MatrixTemp.nu; i++)
    {
        for(int j = 1; j<= MatrixTemp.tu; j++)
        {
            if(i == MatrixTemp.data[j].j)
            {
                pMatrixTemp3->data[q].i = MatrixTemp.data[j].j;
                pMatrixTemp3->data[q].j = MatrixTemp.data[j].i;
                pMatrixTemp3->data[q].e = MatrixTemp.data[j].e;
                q++;
            }
        }
    }
}
//快速转置
void FastConvert(pMatrix pMatrixTemp3,Matrix MatrixTemp)
{
    int i,j,k,p;

    pMatrixTemp3->mu = MatrixTemp.nu;
    pMatrixTemp3->nu = MatrixTemp.mu;
    pMatrixTemp3->tu = MatrixTemp.tu;

    //1.计算原矩阵每一列的非零元个数,存储到数组中,num[0]不存储
    int *num = (int*)malloc(sizeof(int)*(MatrixTemp.nu+1));
    //2.计算原矩阵每一列第一个非零元在新矩阵pMatrixTemp3->data中的位置
    int *cpot = (int*)malloc(sizeof(int)*(MatrixTemp.nu+1));
    if(num == NULL || cpot==NULL)
    {
        return;
    }
    if(MatrixTemp.tu > 0)//原矩阵中存在非零元
    {
        for(i = 1; i <= MatrixTemp.nu;i++)
        {
            num[i] = 0;//每一列的非零元个数初始化为0
        }
        for(j = 1; j <= MatrixTemp.tu; j++)
        {
            ++num[MatrixTemp.data[j].j];//求原矩阵每一列的非零元个数
        }
        cpot[1] = 1;
        for(k = 2;k <= MatrixTemp.nu; k++)
        {
            //下一列第一个非零元位置为上一列第一个非零元位置加上上一列非零元的个数
            cpot[k] = cpot[k-1]+num[k-1];
        }
        for(p = 1; p <= MatrixTemp.tu;p++)
        {
            j = MatrixTemp.data[p].j;
            k = cpot[j];//在新矩阵中存储的位置
            
            pMatrixTemp3->data[k].i = MatrixTemp.data[p].j;
            pMatrixTemp3->data[k].j = MatrixTemp.data[p].i;
            pMatrixTemp3->data[k].e = MatrixTemp.data[p].e;
            ++cpot[j];//更新存储位置
        }
    }
    free(num);
    free(cpot);
}
void printMatrix(pMatrix pMatrixTemp)
{
    int i;
    cout<<"行数,列数,元素值"<<endl;
    for(i = 1; i <= pMatrixTemp->tu; i++)
    {
        cout<<pMatrixTemp->data[i].i<<","<<pMatrixTemp->data[i].j<<","<<pMatrixTemp->data[i].e<<endl;
    }
}
int comp(int a,int b)
{
    if(a > b)
    {
        return 1;
    }else if(a == b)
    {
        return 0;
    }else
    {
        return -1;
    }
}

测试:

int main()
{
    Matrix matrixTemp1 = {0};
    CreateMatrix(&matrixTemp1);
    //Matrix matrixTemp2 = {0};
    //CreateMatrix(&matrixTemp2);
    
    Matrix matrixTemp3 = {0};
//    AddMatrix(&matrixTemp3,matrixTemp1,matrixTemp2);
//    MulMatrix(&matrixTemp3,matrixTemp1,matrixTemp2);
    Convert(&matrixTemp3,matrixTemp1);
    printMatrix(&matrixTemp3);
    cout<<"------------------"<<endl;
    FastConvert(&matrixTemp3,matrixTemp1);
    printMatrix(&matrixTemp3);
        
    return 0;
}