/*
*任务描述:针对稀疏矩阵,实现10个基本操作
*   1:建立稀疏矩阵 ;
*   2:输出稀疏矩阵 ;
*   3:转置稀疏矩阵 ;
*   4:稀疏矩阵相加 ;
*   5:稀疏矩阵相减;
*   6:稀疏矩阵相乘 ;
主要函数:
*   1.void CreateMatrix(Matrix &M);//创建矩阵
*   2.void Output(Matrix M);//输出矩阵
*   3.void TransposeMatrix1(Matrix &M);//转置矩阵算法1
*   4.void TransposeMatrix2(Matrix &M);//转置矩阵算法2
*   5.void TransposeMatrix3(Matrix &M);//转置矩阵算法3
*   6.void AddMatrix(Matrix &M1,Matrix &M2);//矩阵相加
*   7.void SubtractMatrix(Matrix &M1,Matrix &M2);//矩阵相减
*   8.void MultiplyMatrix(Matrix &M,Matrix &N);//矩阵相乘
*   9.Status Check(Matrix M,int index,int row,int line);//检查矩阵M的数组data中第index个元素的行列数
*   10.void SortByRow(Matrix &M);//行优先冒泡排序
*   11.void SortByLine(Matrix &M);//列优先冒泡排序
*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<iomanip>


using namespace std;


#define OK 1
#define FALSE 0
#define MAXSIZE 10000


typedef int ElemType;
typedef int Status;


typedef struct
{
    int row;//非零元素所在的行
    int line;//非零元素所在的列
    ElemType elem;//非零元素大小
} Triple;//非零元素的三元组类型


typedef struct
{
    Triple data[MAXSIZE];//非零元素数组
    int rownum;//矩阵的行数
    int linenum;//矩阵的列数
    int elemnum;//矩阵的非零元素总数
} Matrix;//矩阵类型


void CreateMatrix(Matrix &M);//创建矩阵
void Output(Matrix M);//输出矩阵
void TransposeMatrix1(Matrix &M);//转置矩阵算法1
void TransposeMatrix2(Matrix &M);//转置矩阵算法2
void TransposeMatrix3(Matrix &M);//转置矩阵算法3
void AddMatrix(Matrix &M1,Matrix &M2);//矩阵相加
void SubtractMatrix(Matrix &M1,Matrix &M2);//矩阵相减
void MultiplyMatrix(Matrix &M,Matrix &N);//矩阵相乘
Status Check(Matrix M,int index,int row,int line);//检查矩阵M的数组data中第index个元素的行列数
void SortByRow(Matrix &M);//行优先冒泡排序
void SortByLine(Matrix &M);//列优先冒泡排序
void Interaction();//输出操作


int main()
{
    Interaction();


    Matrix M,N;
    int operate;
    while(cin>>operate)
    {
        switch(operate)
        {
        case 0:
            return 0;


        case 1:
            cout<<"请输入创建的稀疏矩阵的行数、列数、非0元素个数:";
            cin>>M.rownum>>M.linenum>>M.elemnum;
            CreateMatrix(M);
            break;


        case 2:
            Output(M);
            break;


        case 3:
            cout<<"转置矩阵共3种方法,请输入使用的方法序号(1/2/3):";
            cin>>operate;


            switch(operate)
            {
            case 1:
                TransposeMatrix1(M);
                break;


            case 2:
                TransposeMatrix2(M);
                break;


            case 3:
                TransposeMatrix3(M);
                break;
            }
            break;


        case 4:
INPUT1:
            cout<<"请输入创建的稀疏矩阵的行数、列数、非0元素个数:";
            cin>>N.rownum>>N.linenum>>N.elemnum;
            if(M.rownum!=N.rownum||M.linenum!=N.linenum)
            {
                cout<<"矩阵相加的前提是两个矩阵的行数列数分别相等。请创建合法的矩阵。\n";
                goto INPUT1;
            }


            CreateMatrix(N);
            AddMatrix(M,N);
            break;


        case 5:
INPUT2:
            cout<<"请输入创建的稀疏矩阵的行数、列数、非0元素个数:";
            cin>>N.rownum>>N.linenum>>N.elemnum;
            if(M.rownum!=N.rownum||M.linenum!=N.linenum)
            {
                cout<<"矩阵相减的前提是两个矩阵的行数列数分别相等。请创建合法的矩阵。\n";
                goto INPUT2;
            }


            CreateMatrix(N);
            SubtractMatrix(M,N);
            break;


        case 6:
INPUT3:
            cout<<"请输入创建的稀疏矩阵的行数、列数、非0元素个数:";
            cin>>N.rownum>>N.linenum>>N.elemnum;
            if(M.linenum!=N.rownum)
            {
                cout<<"矩阵相乘的前提是矩阵1的列数等于矩阵2的行数。请创建合法的矩阵。\n";
                goto INPUT3;
            }


            CreateMatrix(N);
            MultiplyMatrix(M,N);
            break;
        default:
            cout<<"请输入正确的操作数字!\n";
        }
    }
    return 0;
}


void CreateMatrix(Matrix &M)//创建矩阵
{
    cout<<"请输入"<<M.elemnum<<"个非0元素的行数、列数(均从1开始)、元素大小:\n";
    for(int i=1; i<=M.elemnum; i++)
    {
        cin>>M.data[i].row>>M.data[i].line>>M.data[i].elem;
    }


    SortByRow(M);//将矩阵的所有非零元素按照行优先的顺序重新排列,便于后续操作
    cout<<"创建的稀疏矩阵为:\n";
    Output(M);
}


void Output(Matrix M)//输出矩阵
{
    int index=1;
    for(int row=1; row<=M.rownum; row++)
    {
        for(int line=1; line<=M.linenum; line++)
        {
            if(Check(M,index,row,line))//检测当前位置是否是非零元素
            {
                cout<<setw(4)<<M.data[index].elem;
                index++;
            }
            else
            {
                cout<<setw(4)<<0;
            }
        }
        cout<<endl;
    }
}


void TransposeMatrix1(Matrix &M)//转置矩阵算法1
{
    //算法描述:因为当前矩阵是行优先的,转置后变成列优先的(相对未转置前)。因此
    //枚举列数1——M.linenum,对于每一个列数line,按照原矩阵的顺序遍历一遍所有的非零元素,
    //找出列数等于line的非零元素并完成转置该元素。
    Matrix T;
    T.rownum=M.linenum;
    T.linenum=M.rownum;
    T.elemnum=M.elemnum;


    if(T.elemnum)
    {
        int index1=1;
        for(int line=1; line<=M.linenum; line++)//枚举列数1——M.linenum
        {
            for(int index2=1; index2<=M.elemnum; index2++)//遍历一遍所有的非零元素
            {
                if(M.data[index2].line==line)//找出列数等于line的非零元素
                {
                    //转置该元素
                    T.data[index1].row=M.data[index2].line;
                    T.data[index1].line=M.data[index2].row;
                    T.data[index1].elem=M.data[index2].elem;
                    index1++;
                }
            }
        }
    }


    M=T;//交接矩阵
    cout<<"转置后的稀疏矩阵为:\n";
    Output(M);
}


void TransposeMatrix2(Matrix &M)//转置矩阵算法2
{
    //算法描述:增加两个数组:num[M.linenum+1]与cpot[M.linenum+1]
    //num[line]:矩阵M第line列中非零元素的总个数;
    //cpot[line]:M中第line列当前非零元素在M.data[]中的下标(初始化为当前列中第一个非零元素的下标)
    //遍历一遍原矩阵,对当前遍历到的第index个元素,cpot[M.data[index].line]即为该元素在转置后的矩阵中
    //data数组中的下标,一步定位。
    Matrix T;
    T.rownum=M.linenum;
    T.linenum=M.rownum;
    T.elemnum=M.elemnum;


    if(T.elemnum)
    {
        int num[M.linenum+1];
        memset(num,0,sizeof(num));//初始化num数组
        for(int index=1; index<=M.elemnum; index++)//求num数组
        {
            num[M.data[index].line]++;
        }


        int cpot[M.linenum+1];
        int index=0;
        while(num[++index]==0);
        cpot[index]=1;//第一个该列中存在非零元素的列数在cpot中的值为1
        for(int index2=index+1; index2<=M.linenum; index2++)//递推求cpot数组
        {
            cpot[index2]=cpot[index2-1]+num[index2-1];
        }


        for(index=1; index<=M.elemnum; index++)
        {
            int line=M.data[index].line;
            int index1=cpot[line];//直接定位当前元素转置后在新矩阵data数组中的下标
            T.data[index1].row=M.data[index].line;
            T.data[index1].line=M.data[index].row;
            T.data[index1].elem=M.data[index].elem;
            cpot[line]++;//更新指示的位置
        }
    }


    M=T;
    cout<<"转置后的稀疏矩阵为:\n";
    Output(M);
}


void TransposeMatrix3(Matrix &M)//转置矩阵算法3
{
    //算法描述:不需要开辟新数组的内存,直接按照列优先的原则对
    //原矩阵的所有非零元素进行冒泡排序。排序后,对矩阵所有非零元素
    //交换行列数,即完成转置。
    SortByLine(M);//列优先排序


    for(int index=1; index<=M.elemnum; index++)
    {
        swap(M.data[index].line,M.data[index].row);//交换行列数
    }


    swap(M.linenum,M.rownum);
    cout<<"转置后的稀疏矩阵为:\n";
    Output(M);
}


void AddMatrix(Matrix &M1,Matrix &M2)//矩阵相加
{
    Matrix M;
    M.rownum=M1.rownum;
    M.linenum=M1.linenum;


    int index1=1,index2=1,index=1;
    for(int row=1; row<=M.rownum; row++)
    {
        for(int line=1; line<=M.linenum; line++)
        {
            if(Check(M1,index1,row,line)&&Check(M2,index2,row,line))
            {
                M.data[index].elem=M1.data[index1].elem+M2.data[index2].elem;
                M.data[index].row=row;
                M.data[index].line=line;
                index1++;
                index2++;
                index++;
            }
            else if(Check(M1,index1,row,line)&&!Check(M2,index2,row,line))
            {
                M.data[index].elem=M1.data[index1].elem;
                M.data[index].row=row;
                M.data[index].line=line;
                index1++;
                index++;
            }
            else if(!Check(M1,index1,row,line)&&Check(M2,index2,row,line))
            {
                M.data[index].elem=M2.data[index2].elem;
                M.data[index].row=row;
                M.data[index].line=line;
                index2++;
                index++;
            }
        }
    }
    M.elemnum=index-1;


    M1=M;
    Output(M);
    cout<<"相加后的矩阵是:\n";
    Output(M1);
}


void SubtractMatrix(Matrix &M1,Matrix &M2)//矩阵相减
{
    Matrix M;
    M.rownum=M1.rownum;
    M.linenum=M1.linenum;


    int index1=1,index2=1,index=1;
    for(int row=1; row<=M.rownum; row++)
    {
        for(int line=1; line<=M.linenum; line++)
        {
            if(Check(M1,index1,row,line)&&Check(M2,index2,row,line))
            {
                M.data[index].elem=M1.data[index1].elem-M2.data[index2].elem;
                M.data[index].row=row;
                M.data[index].line=line;
                index1++;
                index2++;
                index++;
            }
            else if(Check(M1,index1,row,line)&&!Check(M2,index2,row,line))
            {
                M.data[index].elem=M1.data[index1].elem;
                M.data[index].row=row;
                M.data[index].line=line;
                index1++;
                index++;
            }
            else if(!Check(M1,index1,row,line)&&Check(M2,index2,row,line))
            {
                M.data[index].elem=-M2.data[index2].elem;//此处变为其相反数
                M.data[index].row=row;
                M.data[index].line=line;
                index2++;
                index++;
            }
        }
    }
    M.elemnum=index-1;


    M1=M;
    cout<<"相减后的矩阵是:\n";
    Output(M1);
}


void MultiplyMatrix(Matrix &M,Matrix &N)//矩阵相乘
{
    //算法描述:先对矩阵N进行列优先排序(M已经为行优先);
    // 在结果矩阵Q可能存在非零元素的情况下:
    //枚举Q的每一行row,每一列line,设Q在(row,line)处的值为temp,
    //在(row,line)下枚举矩阵M中行数等于row的所有元素M.data[index1]
    //在每个M.data[index1]下,枚举列数等于line的矩阵N 中的所有元素N.data[index3],
    //对每个N.data[index3],当N.data[index3].row等于M.data[index1].line时,两个元素位置匹配相乘即可,
    //累加到temp上(temp=temp+N.data[index3].elem*M.data[index1].elem);
    //当前行列(row,line)遍历完成后,temp的值即可求出。
    //使用了四个下标:index1,index2,index3,index4
    //2和4是辅助更新的下标,详见程序。  9
    SortByLine(N);//对矩阵N进行列优先排序
    Matrix Q;
    Q.rownum=M.rownum;
    Q.linenum=N.linenum;
    Q.elemnum=0;


    int index=1;
    if(M.elemnum*N.elemnum)
    {
        int index1,index2=1;
        //index1是矩阵M的遍历器;
        //index2辅助更新M矩阵元素遍历起点,其值为矩阵M中第一个行数等于当前row的元素下标
        for(int row=1; row<=Q.rownum; row++)//枚举Q的每一行row
        {
            int index3,index4=1;
            //index3是矩阵N的遍历器;
            //index4辅助更新N矩阵元素遍历起点,其值为矩阵N中第一个列数等于当前line的元素下标
            for(int line=1; line<=Q.linenum; line++)//每一列line
            {
                int temp=0;//Q在(row,line)处的值
                for(index1=index2; index1<=M.elemnum&&M.data[index1].row==row; index1++)
                    //在index1不越界且M的第index1个元素在第row行的前提下遍历M的元素
                {
                    for(index3=index4; index3<=N.elemnum&&N.data[index3].line==line; index3++)
                        //在index3不越界且N的第index3个元素在第line列的前提下遍历N的元素
                    {
                        if(M.data[index1].line==N.data[index3].row)//两个元素位置匹配相乘即可
                        {
                            temp=temp+M.data[index1].elem*N.data[index3].elem;//累加到temp上
                        }
                    }


                    if(index1==M.elemnum||M.data[index1+1].row!=row)
                        //当矩阵M的所有在第row行的元素遍历完成一遍后(index1==M.elemnum针对矩阵M的最后一行)
                    {
                        index4=index3;
                        //此时N.data[index3].line=line+1,将该下标值复制到index4中,下次遍历下一列时无需从头开始
                    }
                }


                if(temp)
                {
                    Q.data[index].row=row;
                    Q.data[index].line=line;
                    Q.data[index].elem=temp;
                    index++;
                }


                if(line==Q.linenum)
                    //当矩阵Q的第row行求值完成后
                {
                    index2=index1;
                    //此时M.data[index1].row=row+1,将该下标值复制到index2中,下次遍历下一行时无需从头开始
                }
            }
        }
        Q.elemnum=index-1;
    }


    M=Q;
    cout<<"相乘后的稀疏矩阵为:\n";
    Output(M);
}


Status Check(Matrix M,int index,int row,int line)//检查矩阵M的数组data中第index个元素的行列数
{
    if(index<=M.elemnum&&M.data[index].row==row&&M.data[index].line==line)
    {
        return OK;
    }
    return FALSE;
}


void SortByRow(Matrix &M)//行优先冒泡排序
{
    if(M.elemnum)
    {
        for(int i=1; i<=M.elemnum; i++)
        {
            for(int j=i+1; j<=M.elemnum; j++)
            {
                if(M.data[i].row>M.data[j].row||(M.data[i].row==M.data[j].row&&M.data[i].line>M.data[j].line))
                {
                    swap(M.data[i],M.data[j]);
                }
            }
        }
    }
}


void SortByLine(Matrix &M)//列优先冒泡排序
{
    if(M.elemnum)
    {
        for(int i=1; i<=M.elemnum; i++)
        {
            for(int j=i+1; j<=M.elemnum; j++)
            {
                if(M.data[i].line>M.data[j].line||(M.data[i].line==M.data[j].line&&M.data[i].row>M.data[j].row))
                {
                    swap(M.data[i],M.data[j]);
                }
            }
        }
    }
}


void Interaction()//输出操作
{
    cout<<"请输入对应操作的序号:\n";
    cout<<"0:退出程序 ;\n";
    cout<<"1:建立稀疏矩阵 ;\n";
    cout<<"2:输出稀疏矩阵 ;\n";
    cout<<"3:转置稀疏矩阵 ;\n";
    cout<<"4:稀疏矩阵相加 ;\n";
    cout<<"5:稀疏矩阵相减;\n";
    cout<<"6:稀疏矩阵相乘 ;\n";
}