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

实现效果:
1、编写程序任意输入一个稀疏矩阵,用三元组顺序表压缩存储稀疏矩阵
2、对稀疏矩阵进行转置输出转置后的矩阵。


实验目的

对应《数据结构(C语言版)》 第5章 数组与广义表 实验:

1、 掌握下三角矩阵的输入、输出、压缩存储算法;
2、 理解稀疏矩阵的三元组表类型定义
3、 掌握稀疏矩阵的输入、输出、转置算法。


一、基本概念

o(* ̄︶ ̄*)o请先确保理清一下概念

1.稀疏矩阵

假设m*n的矩阵中,有t的非零元,令s=t/m * n,当,s<=0.05时,称此矩阵为稀疏矩阵,简单理解就是非零元特别少的矩阵

//一般矩阵a
    1 2 3
 a= 4 5 6
    7 8 9
    
//稀疏矩阵s
    0 0 0 0 0 
    0 2 0 0 5
 s= 0 0 3 0 0
    0 0 0 0 4

2.矩阵转置

矩阵的转置实际上就是将数据元素的行标和列标互换,即 T(i,j) = M(j,i)
在这里插入图片描述

对应三元组的转置
在这里插入图片描述

3.快速转置算法

矩阵的转置过程经历了三个步骤:

  • 矩阵的行数 n 和列数 m 的值交换;
  • 将三元组中的 i 和 j 调换;
  • 转换之后的表同样按照行序(置换前的列序)为主序,进行排序;【两者不同之处】

快速转置算法,预先确定矩阵M中每一列的第一个非零元在转置的三元组中的位置。

时间复杂度由O(nu * tu)提升到O(nu + tu),尤其是在矩阵的非零元个数tu与mu * nu数量级越接近时差别越明显!

二、完整代码(附详细注释)

提示:本实验环境为VS2019(‾◡◝)

代码如下(示例):

//Matrix.cpp
//任意输入一个稀疏矩阵,并输出其转置矩阵
#include <stdio.h>
#include <stdlib.h>
#include "SparseMatrix.h"

void TransposeSMatrix(TSMatrix M, TSMatrix& T);
void FastTransposeSMatrix(TSMatrix M, TSMatrix& T);

int main()
{
    TSMatrix M,T;
    //创建稀疏矩阵
    CreateSMartrix(M);
    PrintSMatrix(M);

    printf("1.普通转置\t2.快速转置\t3.退出\n");
    printf("请选择对矩阵的操作:\n");
    int choice = 1;
    while (scanf_s("%d", &choice)) {
        switch (choice) {
        case 1:
            //转置
            TransposeSMatrix(M, T);
            PrintSMatrix(T);
            printf("是否继续操作:");
            break;
        case 2:
            //快速转置
            FastTransposeSMatrix(M, T);
            PrintSMatrix(T);
            printf("是否继续操作:");
            break;
        default:
            printf("程序结束");
            exit(0);          
        }
    }
    return 0;
}

//普通转置,按照三元组在转置矩阵中的存储位置转换
void TransposeSMatrix(TSMatrix M, TSMatrix& T) {
    T.mu = M.mu;//行数
    T.nu = M.nu;//列数
    T.tu = M.tu;//非零元的个数
    if (T.tu) {
        int q = 1;
        for (int col = 1; col <= M.mu; ++col) {
            for (int p = 1; p <= M.nu; ++p) {
                if (M.data[p].j == col) {
                    T.data[q].i = M.data[p].j;
                    T.data[q].j = M.data[p].i;
                    T.data[q].e = M.data[p].e;
                    ++q;
                }
            }
        }
    }
}

//快速转置,按照三元组在原矩阵中的位置转换
//即预先确定M中每一列的第一个元素所在的位置
void FastTransposeSMatrix(TSMatrix M, TSMatrix& T) {
    T.mu = M.mu;//行数
    T.nu = M.nu;//列数
    T.tu = M.tu;//非零元的个数
    int* num = (int*)malloc(M.nu * sizeof(int));//num[col]表示矩阵M中第col列中的非零元素的个数
    int* cpot = (int*)malloc(M.nu * sizeof(int));//cpot[col]指示M中第col列的第一个非零元素在T的位置
    int q, col;
    if (T.tu) {//当矩阵不是零矩阵的时候执行操作
        for (col = 1; col <= M.nu; ++col)
            num[col] = 0;//初始化全部设置为0
        for (int t = 1; t <= M.tu; ++t)
            ++num[M.data[t].j];//按创建三元组的顺序,每列有非零元素时num加一
        cpot[1] = 1;
        for (col = 2; col <= M.nu; ++col)
            cpot[col] = cpot[col - 1] + num[col - 1];
        for (int p = 1; p <= M.tu; ++p) {
            col = M.data[p].j;
            q = cpot[col];
            T.data[q].i = M.data[p].j;
            T.data[q].j = M.data[p].i;
            T.data[q].e = M.data[p].e;
            ++cpot[col];
        }
    }
}

//SparseMatrix.h
#pragma once
#define MAXSIZE 12500 //非零元最大个数

//三元组
typedef struct {
	int i, j;//该元素的行、列
	int e;//该元素的值,此例为整型
}Triple;

//稀疏矩阵
typedef struct {
	Triple data[MAXSIZE + 1];//非零元素三元组,data[0]未用,即矩阵的第一个元素坐标表示为(1,1)
	int mu, nu, tu;//稀疏矩阵的行、列、非零元的个数
}TSMatrix;


//创建稀疏矩阵,采用三元组顺序压缩存储的方式
void CreateSMartrix(TSMatrix& M) {
	printf("请依次输入矩阵的大小:\n行数m\t列数n\t非零元个数t\n");
	int m, n, t;
	scanf_s("%d\t%d\t%d", & m, &n, &t);
	M.mu = m;
	M.nu = n;
	M.tu = t;

	printf("请依次输入矩阵非零元的三元组:\n行坐标i\t列坐标j\t元素值e\n");
	int i, j, e;
	for (int i = 1; i <= t; i++)
	{
		scanf_s("%d\t%d\t%d", &i, &j, &e);
		M.data[i].i = i;
		M.data[i].j = j;
		M.data[i].e = e;
	}
}

//输出稀疏矩阵
void PrintSMatrix(TSMatrix M)
{
	printf("------------------------------\n");
	printf("矩阵的三元组表示:\n");
	printf("i\tj\te\n");
	for (int i = 1; i <= M.tu; i++)
	{
		printf("%d\t%d\t%d\n", M.data[i].i, M.data[i].j, M.data[i].e);
	}
	printf("------------------------------\n");
}

题外话

☆*: .。. o(≧▽≦)o .。.:*☆
最近在学习数据结构😉
也想通过写文章锻炼锻炼自己🤣
之后会持续更新后续上机实验的(暗示😶‍🌫️)
不足的地方希望友友们指正,欢迎和我讨论呀😁

  • 16
    点赞
  • 82
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 三元组顺序表是一种存储稀疏矩阵的方式,可以用来示矩阵中非零元素的位置和值。其中,每个三元组三个元素:行号、列号和元素值。 要实现两个矩阵的相加和相减,需要先将它们转换成三元组顺序表的形式,然后按照行号和列号的顺序进行遍历,将相同位置的元素相加或相减,最后得到结果矩阵的三元组顺序表转置操作可以通过交换每个三元组的行号和列号来实现。具体地,对于一个三元组 (i, j, v),它在转置后的矩阵中的位置应该是 (j, i, v)。 总之,使用三元组顺序表存储稀疏矩阵可以方便地实现矩阵的加减和转置操作。 ### 回答2: 三元组顺序表是一种稀疏矩阵存储方式,通过记录非零元素的值、所在行列号来压缩示大量零元素的矩阵,节约存储空间。实现两个矩阵的相加、相减与转置,需要按照三元组顺序表存储方式,对两个矩阵的数据进行处理。 1. 三元组顺序表存储方式: 三元组顺序表的每个元素由三个部分组成:非零元素值、所在行号、所在列号。非零元素在三元组中按行、列顺序排列,同一行的元素按列递增排序。例如,一个5*5的矩阵: 0 0 1 0 0 0 2 0 3 0 4 0 0 0 5 0 6 0 7 8 0 0 9 10 0 可以用三元组顺序表示为: (5, 5, 7) # 稀疏矩阵的行列数、非零元素个数 [(1, 3, 1), (2, 2, 2), (2, 4, 3), (3, 1, 4), (3, 5, 5), (4, 2, 6), (4, 4, 7), (4, 5, 8), (5, 3, 9), (5, 4, 10)] # 非零元素的三元组 2. 稀疏矩阵相加、相减: 对于两个矩阵的相加、相减,需要先将它们的三元组按行列号排序,然后按照顺序遍历两个三元组,将行列号相同的元素相加或相减,得到新的三元组。具体步骤如下: (1) 将两个矩阵的三元组按行列号排序 (2) 从头开始遍历两个三元组,若行列号相同,则将两元素相加或相减,并加入结果矩阵的三元组中 (3) 若行列号不同,则将较小的行列号的元素加入结果矩阵的三元组中 (4) 若一个三元组遍历完,则将另一个三元组的剩余元素加入结果矩阵的三元组中 3. 稀疏矩阵转置: 对于矩阵的转置,同样需要将矩阵的三元组按行列号排序。然后,遍历三元组,将每个元素的行列号交换,并插入到转置后的三元组中。具体步骤如下: (1) 将矩阵的三元组按行列号排序 (2) 从头开始遍历三元组,将每个元素的行列号交换,并插入到转置后的三元组中 以上就是用三元组顺序表存储稀疏矩阵实现两个矩阵的相加、相减与转置的方法。矩阵相加、相减的时间复杂度为O(n),转置矩阵的时间复杂度为O(nlogn)。 ### 回答3: 稀疏矩阵是指大部分元素为0的矩阵,因为这些元素对于运算并没有实质性的作用,所以使用三元组顺序表存储稀疏矩阵可以极大地提高运算效率。 三元组顺序表是一种以三元组的形式进行存储数据结构,以此存储稀疏矩阵可以节省存储空间。其中,每个三元组都包三个数据项,分别是该非零元素的行数、列数以及元素值,可以示为(i, j, value)。 相加与相减 使用三元组顺序表存储两个稀疏矩阵,可以通过从数组中遍历每个非零元素,并比较其在两个矩阵中的位置来实现两个矩阵的加减。具体步骤如下: 1. 遍历两个矩阵的三元组数组,分别找到相同行数和列数的非零元素。 2. 比较两个矩阵相同位置的元素大小,决定是相加还是相减。 3. 若某一矩阵当前行或列已经遍历完,而另一矩阵还有未遍历到的行或列,则将剩余部分复制到结果数组中。 转置 稀疏矩阵转置是指将矩阵中所有元素绕对角线翻转,即将矩阵的行和列交换。对于三元组顺序表来说,转置操作需要改变存储方式,即改变原先每个元素的行数和列数,将其进行交换,同时保留其元素值不变。 具体步骤如下: 1. 读取原矩阵中的每一个三元组(i, j, value)。 2. 将该三元组的行数和列数对换(i,j变为j,i),并将它的元素值存入新矩阵中它对应的位置。 3. 将新矩阵中所有三元组按行数从小到大进行排序,使其成为三元组顺序表。 4. 输出结果矩阵。 总之,使用三元组顺序表存储稀疏矩阵,可以有效节省运算时间和存储空间。相加、相减和转置都可以通过遍历矩阵中的三元组实现,对于数据处理的稀疏矩阵,这种存储方式可以提高运算效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值