【数据结构】三元组表的定义以及快速转置

这篇具有很好参考价值的文章主要介绍了【数据结构】三元组表的定义以及快速转置。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

⭐️写在前面的话⭐️

📒博客主页: 程序员好冰
🎉欢迎 【点赞👍 关注🔎 收藏⭐️ 留言📝】
📌本文由 程序员好冰 原创,CSDN 首发!
📆入站时间: 🌴2022 年 07 月 13 日🌴
✉️ 是非不入松风耳,花落花开只读书。
💭推荐书籍:📚《Java编程思想》,📚《Java 核心技术卷》
💬参考在线编程网站:🌐牛客网🌐力扣
🍭 作者水平很有限,如果发现错误,一定要及时告知作者哦!感谢感谢!🍭


三元组顺序表的定义与使用

存在一种矩阵,其非零元较零元少,而且分布没有一定的规律,就是稀疏矩阵;通常认为稀疏矩阵的稀疏因子小于或等于0.05。

然而,在存储稀疏矩阵时,通常不会按照普通的方法,将零元也进行操作,而是会通过三元组将稀疏矩阵进行压缩

其思想是:只存入非零元,通过行标和列标记录非零元的逻辑上的二维坐标,其余的元素就默认是零元。

传递二维数组参数(固定维度和不固定维度两种)

参考这篇文章

1、三元组的定义

#include <stdio.h>
#include <stdlib.h>

//稀疏矩阵:矩阵中的非零元素比较少

//三元组的结点定义
#define MAX_SIZE 100//表中非零元素个数的最大值

typedef int ElemType;

//三元组结点定义
typedef struct Triple
{
    //三元组中非零元素的行下标和列下标
    int row;
    int col;
    ElemType e;//非零元素对应的值
}Triple;

//三元组顺序表定义
typedef struct TSMatrix
{
    Triple data[MAX_SIZE+1];//多余的一个位置用于存放非零元的个数
    int m_row,m_col,m_num;//矩阵的行数、列数(固定)和非零元的个数
}TSMatrix;

2、创建稀疏矩阵

void creatSMatrix(ElemType *mat,int row,int col)
{
    int i,j;
    printf("请按行依次输入这个矩阵的元素:\n");
    for(i=1;i<=row;i++){
        for(j=1;j<=col;j++){
            scanf("%d",(mat+(i-1)*col+j));
        }
    }
}

3、打印稀疏矩阵

void printSMatrix(ElemType *mat,int row,int col)
{
    printf("原始矩阵为:\n");
    int i,j;
    for(i=1;i<=row;i++){
        for(j=1;j<=col;j++){
            printf("%d\t",*(mat+(i-1)*col+j));
        }
        printf("\n");
    }
    printf("----------------------------------\n");
}

4、将稀疏矩阵转为三元组矩阵

//对三元组进行处理
void initTriple(TSMatrix *M,ElemType *mat,int row,int col)
{
    M->m_row=0;
    M->m_num=0;
    M->m_col=3;//三元组矩阵默认为三列
    int i,j;
    for(i=1;i<=row;i++){
        for(j=1;j<=col;j++){
            if(*(mat+(i-1)*col+j)!=0){
                //非零元数增加一个
                M->m_num++;
                M->m_row++;
                M->data[M->m_num].row=i;
                M->data[M->m_num].col=j;
                M->data[M->m_num].e=*(mat+(i-1)*col+j);
            }
        }
    }
    //第0号位置存放的是原始矩阵的行数和列数,以及非零元的个数
    M->data[0].row=row;
    M->data[0].col=col;
    M->data[0].e=M->m_num;
}

5、打印三元组矩阵

void printTriple(TSMatrix M)
{
    //打印三元组
    printf("三元组矩阵为:\n");
    printf("行\t列\t值\n");
    int i;
    for(i=0;i<=M.m_row;i++){
        printf("%d\t%d\t%d\n",M.data[i].row,M.data[i].col,M.data[i].e);
    }
    printf("----------------------------------\n");
}

6、将三元组矩阵转为稀疏矩阵并打印

//将三元组表还原为稀疏矩阵
void printSMatrix2(TSMatrix M)
{
    int i,j;
    int row=M.data[0].row;
    int col=M.data[0].col;
    ElemType mat2[row][col];
    //写法一(比较常规)
    //写法二(数组中的每个元素默认值都为0)
    for(i=1;i<=M.m_num;i++){
        mat2[M.data[i].row][M.data[i].col]=M.data[i].e;
    }
    printf("原始矩阵为:\n");
    for(i=1;i<=row;i++){
        for(j=1;j<=col;j++){
            printf("%d\t",mat2[i][j]);
        }
        printf("\n");
    }
    printf("----------------------------------\n");
}

7、转置三元组矩阵

我们知道,稀疏矩阵的转置需要经历以下 3 步

  1. 将矩阵的行数和列数互换;
  2. 将三元组表(存储矩阵)中的 i 列和 j 列互换,实现矩阵的转置;
  3. 以 j 列为序,重新排列三元组表中存储各三元组的先后顺序。
  • 由于三元组表的第0行存放的是稀疏矩阵的信息,所以只进行交换,不进行重排。

三元组表的转置,数据结构,算法

方法一(先按列的次序排序,再交换行列)

对矩阵M的col的值进行冒泡排序,由于M是以行序为主序排列的,说明对col的相同值来说,已经是排好序的了,因此不必再对row的值进行冒泡排序。

操作过程中,将col列中的最小值提出,放到转置矩阵T的第一行,注意行列交换,值value不改变。

三元组表的转置,数据结构,算法

同样的思路:先交换行列,再进行行排序

//普通转置思路
//参数中M指原三元组表,值传递
//参数中T指转置后的三元组表,引用传递
void TransposeSMatrix(TSMatrix M,TSMatrix *T)
{
    int T_index;用于遍历T的非0行,共遍历t_num次
    int M_col;//记录三元组表M的列的数值,应该从1递增
    int M_index;//用于遍历M的非0行,共遍历m_num次
    //先将M的一些初始信息赋值为T
    T->m_row=M.m_row;
    T->m_col=M.m_col;
    T->m_num=M.m_num;
    T->data[0].row=M.data[0].col;
    T->data[0].col=M.data[0].row;
    T->data[0].e=M.data[0].e;//这相当于处理完了三元组表的第0行
    if(T->m_num>0){
        T_index=1;
        for(M_col=1;M_col<=M.m_col;M_col++){
            //这里的M_index从1开始,是因为我们上面已经处理好的第0行
            for(M_index=1;M_index<=M.m_num;M_index++){
                if(M.data[M_index].col==M_col){
                    T->data[T_index].row=M.data[M_index].col;
                    T->data[T_index].col=M.data[M_index].row;
                    T->data[T_index].e=M.data[M_index].e;
                    T_index++;
                }
            }
        }
    }
}

方法二(快速转置算法)

可以参考一下这个文章

稀疏矩阵快速转置算法和普通算法的区别仅在于第 3 步,快速转置能够做到遍历一次三元组表即可完成第 3 步的工作。

初步思路:统计M矩阵列中小于col值的个数,加上1就是转置后T矩阵中所对应的行数。

​ 若col值存在相同的,则进行累加。

可以发现这种思路的时间复杂度同样挺高的,甚至和方法一的思路类似。

实际算法:

注意

这里通过两个数组来缩短算法的时间复杂度

  • 记录稀疏矩阵每一列非零元素的个数a[col],第1列有1个非零元,第2列有2个非零元。

​ a[1]=1;a[2]=2;

  • 记录稀疏矩阵中每一列第1个非零元素在转置后的三元表中的位置b[col],由转置的性质我们可以知道,转置相当于将原先按行展开的形式按列展开;故第1列的首非零元会放到转置后的三元表的第1个位置上(第0个位置上有其它信息)。

​ b[1]=1;b[2]=2。

b[col]=b[col-1]+a[col-2]

解释一下:由于我们的稀疏矩阵是从第0行第0列开始的,所以这里的a[col-2]是减2,而不是减1。

后一列首个非 0 元素存放的位置等于前一列首个非 0 元素的存放位置加上该列非 0 元素的个数。

//三元组表的快速转置
/*
思路:
    按列查找每一列中的首非零元以及非零元的个数,并使用两个数组存储起来
    有cpot[n]=cpot[n-1]+num[n-1]
    并规定cpot[1]=1
    注意:这里不考虑稀疏矩阵或是三元组表的0行0列
*/
void FastTransposeSMatrix(TSMatrix M,TSMatrix *T2)
{
    int T2_index;用于遍历T的非0行,共遍历t_num次
    int M_col;//记录三元组表M的列的数值,应该从1递增
    int M_index;//用于遍历M的非0行,共遍历m_num次

    int num[MAX_SIZE];//用于记录M中每一列的非零元素
    int cpot[MAX_SIZE];//用于记录M中每一列的首非零元素应该在T中的index(从1开始)

    //首先,分别从表结构和非零元两个方面赋值T2
    T2->m_row=M.m_row;
    T2->m_col=M.m_col;
    T2->m_num=M.m_num;
    T2->data[0].row=M.data[0].col;
    T2->data[0].col=M.data[0].row;
    T2->data[0].e=M.data[0].e;

    if(T2->m_num>0){
        //将数组num中的每个元素置0,防止默认值
        for(M_col=1;M_col<=M.m_col;M_col++){
            num[M_col]=0;
        }
        //遍历稀疏矩阵每一列,统计非零元的数量
        for(M_index=1;M_index<=M.m_num;M_index++){
            num[M.data[M_index].col]++;
        }

        //由于转置后相当于按列展开
        //默认(稀疏矩阵从第1行第1列开始)
        cpot[1]=1;

        for(M_col=2;M_col<=M.m_col;M_col++){
            cpot[M_col]=cpot[M_col-1]+num[M_col-1];
        }
        //遍历M的每一行
        for(M_index=1;M_index<=M.m_num;M_index++){
            //取每一行的列下标
            M_col=M.data[M_index].col;
            //带入cpot[]数组中,找到在T中的下标
            //cpot中存有所有非零元的位置信息
            T2_index=cpot[M_col];
            //互换信息
            T2->data[T2_index].row=M.data[M_index].col;
            T2->data[T2_index].col=M.data[M_index].row;
            T2->data[T2_index].e=M.data[M_index].e;
            //这个值是根据列来自增的
            //即每一列中除了首非零元,还剩下几个非零元就加几次
            cpot[M_col]++;
        }
    }
}

主函数

int main()
{
    printf("初始化稀疏矩阵...\n");
    int row,col;
    printf("请输入矩阵的行数和列数(row,col):");
    scanf("%d,%d",&row,&col);
    printf("\n");
    ElemType mat[row][col];
    TSMatrix M;
    TSMatrix T;
    TSMatrix T2;

    //创建稀疏矩阵
    creatSMatrix(*mat,row,col);
    printf("----------------------------------\n");
    //打印稀疏矩阵
    printSMatrix(*mat,row,col);
    //将稀疏矩阵转为三元组
    initTriple(&M,*mat,row,col);
    //打印三元组
    printTriple(M);
    //将三元组还原,并打印
    printf("还原后的");

    printSMatrix2(M);

    //转置三元组

    /*方法一*/
    TransposeSMatrix(M,&T);
    printf("普通转置后的");
    printTriple(T);
    /*方法二*/
    FastTransposeSMatrix(M,&T2);
    printf("快速转置后的");
    printTriple(T2);
    printf("Hello world!\n");
    return 0;
}

程序源码

运行截图

三元组表的转置,数据结构,算法

#include <stdio.h>
#include <stdlib.h>

//稀疏矩阵:矩阵中的非零元素比较少

//三元组的结点定义
#define MAX_SIZE 100//表中非零元素个数的最大值

typedef int ElemType;

//三元组结点定义
typedef struct Triple
{
    //三元组中非零元素的行下标和列下标
    int row;
    int col;
    ElemType e;//非零元素对应的值
}Triple;

//三元组顺序表定义
typedef struct TSMatrix
{
    Triple data[MAX_SIZE+1];//多余的一个位置用于存放非零元的个数
    int m_row,m_col,m_num;//矩阵的行数、列数(固定)和非零元的个数
}TSMatrix;

void creatSMatrix(ElemType *mat,int row,int col)
{
    int i,j;
    printf("请按行依次输入这个矩阵的元素:\n");
    for(i=1;i<=row;i++){
        for(j=1;j<=col;j++){
            scanf("%d",(mat+(i-1)*col+j));
        }
    }
}

void printSMatrix(ElemType *mat,int row,int col)
{
    printf("原始矩阵为:\n");
    int i,j;
    for(i=1;i<=row;i++){
        for(j=1;j<=col;j++){
            printf("%d\t",*(mat+(i-1)*col+j));
        }
        printf("\n");
    }
    printf("----------------------------------\n");
}

//对三元组进行处理
void initTriple(TSMatrix *M,ElemType *mat,int row,int col)
{
    M->m_row=0;
    M->m_num=0;
    M->m_col=3;//三元组矩阵默认为三列
    int i,j;
    for(i=1;i<=row;i++){
        for(j=1;j<=col;j++){
            if(*(mat+(i-1)*col+j)!=0){
                //非零元数增加一个
                M->m_num++;
                M->m_row++;
                M->data[M->m_num].row=i;
                M->data[M->m_num].col=j;
                M->data[M->m_num].e=*(mat+(i-1)*col+j);
            }
        }
    }
    //第0号位置存放的是原始矩阵的行数和列数,以及非零元的个数
    M->data[0].row=row;
    M->data[0].col=col;
    M->data[0].e=M->m_num;
}


void printTriple(TSMatrix M)
{
    //打印三元组
    printf("三元组矩阵为:\n");
    printf("行\t列\t值\n");
    int i;
    for(i=0;i<=M.m_row;i++){
        printf("%d\t%d\t%d\n",M.data[i].row,M.data[i].col,M.data[i].e);
    }
    printf("----------------------------------\n");
}

//将三元组表还原为稀疏矩阵
void printSMatrix2(TSMatrix M)
{
    int i,j;
    int row=M.data[0].row;
    int col=M.data[0].col;
    ElemType mat2[row][col];
    //写法一(比较常规)
    //写法二(数组中的每个元素默认值都为0)
    for(i=1;i<=M.m_num;i++){
        mat2[M.data[i].row][M.data[i].col]=M.data[i].e;
    }
    printf("原始矩阵为:\n");
    for(i=1;i<=row;i++){
        for(j=1;j<=col;j++){
            printf("%d\t",mat2[i][j]);
        }
        printf("\n");
    }
    printf("----------------------------------\n");
}

//普通转置思路
//参数中M指原三元组表,值传递
//参数中T指转置后的三元组表,引用传递
void TransposeSMatrix(TSMatrix M,TSMatrix *T)
{
    int T_index;用于遍历T的非0行,共遍历t_num次
    int M_col;//记录三元组表M的列的数值,应该从1递增
    int M_index;//用于遍历M的非0行,共遍历m_num次
    //先将M的一些初始信息赋值为T
    T->m_row=M.m_row;
    T->m_col=M.m_col;
    T->m_num=M.m_num;
    T->data[0].row=M.data[0].col;
    T->data[0].col=M.data[0].row;
    T->data[0].e=M.data[0].e;//这相当于处理完了三元组表的第0行
    if(T->m_num>0){
        T_index=1;
        for(M_col=1;M_col<=M.m_col;M_col++){
            //这里的M_index从1开始,是因为我们上面已经处理好的第0行
            for(M_index=1;M_index<=M.m_num;M_index++){
                if(M.data[M_index].col==M_col){
                    T->data[T_index].row=M.data[M_index].col;
                    T->data[T_index].col=M.data[M_index].row;
                    T->data[T_index].e=M.data[M_index].e;
                    T_index++;
                }
            }
        }
    }
}

//三元组表的快速转置
/*
思路:
    按列查找每一列中的首非零元以及非零元的个数,并使用两个数组存储起来
    有cpot[n]=cpot[n-1]+num[n-1]
    并规定cpot[1]=1
    注意:这里不考虑稀疏矩阵或是三元组表的0行0列
*/
void FastTransposeSMatrix(TSMatrix M,TSMatrix *T2)
{
    int T2_index;用于遍历T的非0行,共遍历t_num次
    int M_col;//记录三元组表M的列的数值,应该从1递增
    int M_index;//用于遍历M的非0行,共遍历m_num次

    int num[MAX_SIZE];//用于记录M中每一列的非零元素
    int cpot[MAX_SIZE];//用于记录M中每一列的首非零元素应该在T中的index(从1开始)

    //首先,分别从表结构和非零元两个方面赋值T2
    T2->m_row=M.m_row;
    T2->m_col=M.m_col;
    T2->m_num=M.m_num;
    T2->data[0].row=M.data[0].col;
    T2->data[0].col=M.data[0].row;
    T2->data[0].e=M.data[0].e;

    if(T2->m_num>0){
        //将数组num中的每个元素置0,防止默认值
        for(M_col=1;M_col<=M.m_col;M_col++){
            num[M_col]=0;
        }
        //遍历稀疏矩阵每一列,统计非零元的数量
        for(M_index=1;M_index<=M.m_num;M_index++){
            num[M.data[M_index].col]++;
        }

        //由于转置后相当于按列展开
        //默认(稀疏矩阵从第1行第1列开始)
        cpot[1]=1;

        for(M_col=2;M_col<=M.m_col;M_col++){
            cpot[M_col]=cpot[M_col-1]+num[M_col-1];
        }
        //遍历M的每一行
        for(M_index=1;M_index<=M.m_num;M_index++){
            //取每一行的列下标
            M_col=M.data[M_index].col;
            //带入cpot[]数组中,找到在T中的下标
            //cpot中存有所有非零元的位置信息
            T2_index=cpot[M_col];
            //互换信息
            T2->data[T2_index].row=M.data[M_index].col;
            T2->data[T2_index].col=M.data[M_index].row;
            T2->data[T2_index].e=M.data[M_index].e;
            //这个值是根据列来自增的
            //即每一列中除了首非零元,还剩下几个非零元就加几次
            cpot[M_col]++;
        }
    }
}

int main()
{
    printf("初始化稀疏矩阵...\n");
    int row,col;
    printf("请输入矩阵的行数和列数(row,col):");
    scanf("%d,%d",&row,&col);
    printf("\n");
    ElemType mat[row][col];
    TSMatrix M;
    TSMatrix T;
    TSMatrix T2;

    //创建稀疏矩阵
    creatSMatrix(*mat,row,col);
    printf("----------------------------------\n");
    //打印稀疏矩阵
    printSMatrix(*mat,row,col);
    //将稀疏矩阵转为三元组
    initTriple(&M,*mat,row,col);
    //打印三元组
    printTriple(M);
    //将三元组还原,并打印
    printf("还原后的");

    printSMatrix2(M);

    //转置三元组

    /*方法一*/
    TransposeSMatrix(M,&T);
    printf("普通转置后的");
    printTriple(T);
    /*方法二*/
    FastTransposeSMatrix(M,&T2);
    printf("快速转置后的");
    printTriple(T2);
    printf("Hello world!\n");
    return 0;
}

🚀先看后赞,养成习惯!🚀

🚀 先看后赞,养成习惯!🚀

🎈觉得文章写得不错的老铁们,点赞评论关注走一波!谢谢啦!🎈文章来源地址https://www.toymoban.com/news/detail-738804.html


到了这里,关于【数据结构】三元组表的定义以及快速转置的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 三元组表的快速转置算法

    当我们在存储稀疏矩阵的时候(稀疏矩阵:矩阵中只包含有极少数的非0元素),由于稀疏矩阵只有少量关键元素(就是非0元素),我们将整个稀疏矩阵全部存储是十分浪费存储空间的,如何跳过这些非0元素,只存储关键元素以节约存储空间呢?这个时候,三元组表就出现了

    2024年02月07日
    浏览(35)
  • 【玩转408数据结构】线性表——单链表的定义以及增删改查(线性表的链式表示 上)

            到这里我们已经了解到线性表是具有 相同数据类型 的 有限个数据元素 序列,而线性表的顺序存储也就是顺序表,顺序表的存储形式十分直观,我们在实现时使用数组进行实现,但顺序表在插入或者删除元素时需要移动大量元素,那么怎么样才能在插入删除元素时不

    2024年02月21日
    浏览(40)
  • 【数据结构】顺序表的定义

    🎈个人主页:豌豆射手^ 🎉欢迎 👍点赞✍评论⭐收藏 🤗收录专栏:数据结构 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步! 在数据结构的世界里,顺序表是一种常见且基础的线性数据结构。它以其简洁、直观的特性,广

    2024年04月08日
    浏览(40)
  • 数据结构--单链表的定义

    单链表的定义(如何用代码实现) 优点:不要求大片连续空间,改变容量方便 缺点:不可随机存取,要耗费一定空间存放指针 为了方便 我们经常使用 typedef t y p e d e f 数据类型 别名 color{purple}typedef 数据类型 别名 t y p e d e f 数据类型 别名 代码一: 代码二: 代码一与代码二是

    2024年02月11日
    浏览(43)
  • 【数据结构】单链表的定义和操作

    目录 1.单链表的定义 2.单链表的创建和初始化 3.单链表的插入节点操作 4.单链表的删除节点操作 5.单链表的查找节点操作 6.单链表的更新节点操作 7.完整代码 🌈嗨!我是Filotimo__🌈。很高兴与大家相识,希望我的博客能对你有所帮助。 💡本文由Filotimo__✍️原创,首发于CS

    2024年02月02日
    浏览(37)
  • 【数据结构】顺序表的定义和操作

    目录 1.初始化 2.插入 3.删除 4.查找 5.修改 6.长度 7.遍历 8.完整代码 🌈嗨!我是Filotimo__🌈。很高兴与大家相识,希望我的博客能对你有所帮助。 💡本文由Filotimo__✍️原创,首发于CSDN📚。 📣如需转载,请事先与我联系以获得授权⚠️。 🎁欢迎大家给我点赞👍、收藏⭐️

    2024年02月03日
    浏览(35)
  • 【数据结构】双链表的定义和操作

    目录 1.双链表的定义 2.双链表的创建和初始化 3.双链表的插入节点操作 4.双链表的删除节点操作 5.双链表的查找节点操作 6.双链表的更新节点操作 7.完整代码 🌈嗨!我是Filotimo__🌈。很高兴与大家相识,希望我的博客能对你有所帮助。 💡本文由Filotimo__✍️原创,首发于CS

    2024年02月03日
    浏览(67)
  • 【数据结构】顺序表的定义和运算

    目录 1.初始化 2.插入 3.删除 4.查找 5.修改 6.长度 7.遍历 8.完整代码 🌈嗨!我是Filotimo__🌈。很高兴与大家相识,希望我的博客能对你有所帮助。 💡本文由Filotimo__✍️原创,首发于CSDN📚。 📣如需转载,请事先与我联系以获得授权⚠️。 🎁欢迎大家给我点赞👍、收藏⭐️

    2024年02月05日
    浏览(27)
  • [数据结构(C语言版本)上机实验]稀疏矩阵的三元组顺序表压缩存储以及转置实现(含快速转置)

    实现效果: 1、编写程序任意 输入 一个稀疏矩阵,用 三元组顺序表 压缩存储 稀疏矩阵 。 2、对稀疏矩阵进行 转置 , 输出 转置后的矩阵。 对应《数据结构(C语言版)》 第5章 数组与广义表 实验: 1、 掌握下三角矩阵的输入、输出、压缩存储算法; 2、 理解稀疏矩阵的三元

    2024年02月03日
    浏览(34)
  • 数据结构-图的邻接表的定义与实现

    目录 一、引言 二、图的基本概念 三、图的存储方式 1. 邻接矩阵 2. 邻接表 3. 十字链表 4. 邻接多重表 四、邻接表的实现 1. 邻接表的定义 2. 邻接表的构建 3. 邻接表的遍历 五、邻接表的优缺点 六、总结 在计算机科学中,图是一种非常重要的数据结构,它是由节点和边组成的

    2024年02月03日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包