【数据结构】数组和字符串(三):特殊矩阵的压缩存储:三角矩阵、对称矩阵——一维数组

news2024/11/14 13:59:30

文章目录

  • 4.2.1 矩阵的数组表示
  • 4.2.2 特殊矩阵的压缩存储
    • a. 对角矩阵的压缩存储
    • b. 三角矩阵的压缩存储
      • 结构体
      • 初始化
      • 元素设置
      • 元素获取
      • 打印矩阵
      • 主函数
      • 输出结果
      • 代码整合
    • c. 对称矩阵的压缩存储
      • 元素设置
      • 元素获取
      • 主函数
      • 输出结果
      • 代码整合

4.2.1 矩阵的数组表示

【数据结构】数组和字符串(一):矩阵的数组表示

4.2.2 特殊矩阵的压缩存储

  矩阵是以按行优先次序将所有矩阵元素存放在一个一维数组中。但是对于特殊矩阵,如对称矩阵、三角矩阵、对角矩阵和稀疏矩阵等, 如果用这种方式存储,会出现大量存储空间存放重复信息或零元素的情况,这样会造成很大的空间浪费。为节约存储空间和算法(程序)运行时间,通常会采用压缩存储的方法。

  • 对角矩阵:指除了主对角线以外的元素都为零的矩阵,即对 任意 i ≠ j (1≤ i , j ≤n),都有M(i, j)=0。由于只有主对角线上有非零元素,只需存储主对角线上的元素即可。
  • 三角矩阵:指上三角或下三角的元素都为零的矩阵。同样地,只需存储其中一部分非零元素,可以节省存储空间。
  • 对称矩阵:指矩阵中的元素关于主对角线对称的矩阵。由于对称矩阵的非零元素有一定的规律,可以只存储其中一部分元素,从而减少存储空间。
  • 稀疏矩阵:指大部分元素为零的矩阵。传统的按行优先次序存储方法会浪费大量空间来存储零元素,因此采用压缩存储的方法更为合适。常见的压缩存储方法有:压缩稠密行(CSR)、压缩稠密列(CSC)、坐标列表(COO)等。

a. 对角矩阵的压缩存储

【数据结构】数组和字符串(二):特殊矩阵的压缩存储:对角矩阵——一维数组

b. 三角矩阵的压缩存储

  三角矩阵分为上三角矩阵和下三角矩阵。方阵M是上三角矩阵,当且仅当i > j时有M(i, j)=0 . 方阵M是下三角矩阵,当且仅当i < j时有M(i,j)=0 。这里以下三角矩阵为例,讨论其压缩存储方法:

  考虑一个n×n维下三角矩阵,其第一行至多有1个非零元素,第二行至多有2个非零元素,……,第n行至多有n个非零元素,非零元素至多共有(1+2+…+n) = n(n+1)/2个。可以用大小为n(n+1)/2的一维数组来存储下三角矩阵,换言之,就是要把下三角矩阵M的非零元素映射到一个一维数组d中。映射次序可采用按行优先或按列优先。

  • 假设映射采取按行优先,非零元素M(i, j)会映射到一维数组d中的哪个元素?
    • 设元素M(i, j)前面有k个非零元素,则k可计算如下:
      • k = 1+2+…+(i-1)+(j-1)= i(i-1)/2+j-1
  • 假设映射采取按列优先,非零元素M(i, j)会映射到一维数组d中的哪个元素?

结构体

typedef struct {
    int size;       // 矩阵的维度
    int elements[MAX_SIZE];  // 存储下三角元素的数组
} LowerTriangularMatrix;

  结构体 LowerTriangularMatrix,包含两个成员变量:size 表示矩阵的维度,elements 是一个一维数组,用于存储下三角矩阵的元素。接下来,代码实现了几个函数来进行下三角矩阵的初始化、元素设置、元素获取以及打印矩阵的操作。

初始化

void initialize(LowerTriangularMatrix *matrix, int size) {
    matrix->size = size;

    // 初始化下三角元素数组
    for (int i = 0; i < size * (size + 1) / 2; i++) {
        matrix->elements[i] = 0;
    }
}

  initialize 函数用于初始化下三角矩阵,接受一个指向 LowerTriangularMatrix 结构体的指针以及矩阵的维度作为参数。它将矩阵的维度存储在 size 成员变量中,并将 elements 数组中的所有元素初始化为 0。

元素设置

void setElement(LowerTriangularMatrix *matrix, int row, int col, int value) {
    if (row < col) {
        printf("Error: Only elements in or below the main diagonal can be set.\n");
    } else if (row < 0 || row >= matrix->size || col < 0 || col >= matrix->size) {
        printf("Error: Invalid row or column index.\n");
    } else {
        int index = row * (row + 1) / 2 + col; // 计算压缩存储的索引
        matrix->elements[index] = value;
    }
}

   setElement 函数用于设置下三角矩阵中指定位置的元素值。

  • 它接受一个指向 LowerTriangularMatrix 结构体的指针,以及要设置的元素的行、列索引和值作为参数。
  • 在设置元素之前,它会进行一些错误检查,例如判断行列索引是否有效以及是否在下三角矩阵的主对角线或以下。如果检查通过,它会计算出在压缩存储中的索引,并将指定位置的元素值设置为给定的值。

元素获取

int getElement(LowerTriangularMatrix *matrix, int row, int col) {
    if (row < 0 || row >= matrix->size || col < 0 || col >= matrix->size) {
        printf("Error: Invalid row or column index.\n");
        return 0;
    } else if (row < col) {
        return 0;
    } else {
        int index = row * (row + 1) / 2 + col; // 计算压缩存储的索引
        return matrix->elements[index];
    }
}

  getElement 函数用于获取下三角矩阵中指定位置的元素值。

  • 它接受一个指向 LowerTriangularMatrix 结构体的指针,以及要获取的元素的行、列索引作为参数。
  • 在获取元素之前,它也会进行行列索引的有效性检查。
    • 如果索引无效,它会打印错误消息并返回 0。
    • 如果指定位置在下三角矩阵的主对角线或以下,它会计算出在压缩存储中的索引,并返回相应的元素值。
    • 如果指定位置在主对角线以上,表示该位置应为零,因此直接返回 0。

打印矩阵

void printMatrix(LowerTriangularMatrix *matrix) {
    for (int i = 0; i < matrix->size; i++) {
        for (int j = 0; j < matrix->size; j++) {
            printf("%d ", getElement(matrix, i, j));
        }
        printf("\n");
    }
}

  printMatrix 函数用于打印下三角矩阵。函数使用嵌套的循环遍历矩阵的所有行和列。对于每个位置,如果行索引大于等于列索引,表示该位置存在元素,需要打印 elements 数组中对应的值;否则,表示该位置不存在元素,打印 0。打印完一行后,换行继续打印下一行。

主函数

int main() {
    LowerTriangularMatrix matrix;
    int size = 4;

    initialize(&matrix, size);

    setElement(&matrix, 0, 0, 1);
    setElement(&matrix, 1, 0, 2);
    setElement(&matrix, 1, 1, 3);
    setElement(&matrix, 2, 0, 4);
    setElement(&matrix, 2, 1, 5);
    setElement(&matrix, 2, 2, 6);
    setElement(&matrix, 3, 0, 7);
    setElement(&matrix, 3, 1, 8);
    setElement(&matrix, 3, 2, 9);
    setElement(&matrix, 3, 3, 10);

    printf("Lower Triangular Matrix:\n");
    printMatrix(&matrix);

    return 0;
}

  在 main 函数中,首先创建了一个 LowerTriangularMatrix 结构体变量 matrix,并指定矩阵的维度为 4。然后,通过调用 initialize 函数初始化了矩阵。接下来,通过多次调用 setElement 函数设置了矩阵中的各个元素的值。最后,调用 printMatrix 函数打印了下三角矩阵的内容。

输出结果

在这里插入图片描述

代码整合

#include <stdio.h>

#define MAX_SIZE 100

// 定义下三角矩阵结构体
typedef struct {
    int size;       // 矩阵的维度
    int elements[MAX_SIZE];  // 存储下三角元素的数组
} LowerTriangularMatrix;

// 初始化下三角矩阵
void initialize(LowerTriangularMatrix *matrix, int size) {
    matrix->size = size;

    // 初始化下三角元素数组
    for (int i = 0; i < size * (size + 1) / 2; i++) {
        matrix->elements[i] = 0;
    }
}

// 设置下三角矩阵中指定位置的元素值
void setElement(LowerTriangularMatrix *matrix, int row, int col, int value) {
    if (row < col) {
        printf("Error: Only elements in or below the main diagonal can be set.\n");
    } else if (row < 0 || row >= matrix->size || col < 0 || col >= matrix->size) {
        printf("Error: Invalid row or column index.\n");
    } else {
        int index = row * (row + 1) / 2 + col; // 计算压缩存储的索引
        matrix->elements[index] = value;
    }
}

// 获取下三角矩阵中指定位置的元素值
int getElement(LowerTriangularMatrix *matrix, int row, int col) {
    if (row < 0 || row >= matrix->size || col < 0 || col >= matrix->size) {
        printf("Error: Invalid row or column index.\n");
        return 0;
    } else if (row < col) {
        return 0;
    } else {
        int index = row * (row + 1) / 2 + col; // 计算压缩存储的索引
        return matrix->elements[index];
    }
}

// 打印下三角矩阵
void printMatrix(LowerTriangularMatrix *matrix) {
    for (int i = 0; i < matrix->size; i++) {
        for (int j = 0; j < matrix->size; j++) {
            printf("%d ", getElement(matrix, i, j));
        }
        printf("\n");
    }
}

int main() {
    LowerTriangularMatrix matrix;
    int size = 4;

    initialize(&matrix, size);

    setElement(&matrix, 0, 0, 1);
    setElement(&matrix, 1, 0, 2);
    setElement(&matrix, 1, 1, 3);
    setElement(&matrix, 2, 0, 4);
    setElement(&matrix, 2, 1, 5);
    setElement(&matrix, 2, 2, 6);
    setElement(&matrix, 3, 0, 7);
    setElement(&matrix, 3, 1, 8);
    setElement(&matrix, 3, 2, 9);
    setElement(&matrix, 3, 3, 10);

    printf("Lower Triangular Matrix:\n");
    printMatrix(&matrix);

    return 0;
}

c. 对称矩阵的压缩存储

  n×n方阵M是对称矩阵,当且仅当对任意 i , j (1≤ i , j ≤ n),均有M(i, j) = M( j, i) 。
  因为对称矩阵中M(i, j)与M(j, i)的信息相同,所以只需存储其上三角部分或下三角部分的元素信息。这里参照下三角矩阵的压缩存储方法,即用大小为n(n+1)/2的一维数组来存储,关于对称矩阵中的下三角部分的元素M(i, j) (i ≥ j) ,与下三角矩阵压缩存储的映射公式一样,映射到d[k](其中k= i(i-1)/2+( j-1) );关于对称矩阵之上三角部分的元素M(i, j)(i< j,不包含对角线上的元素),因其元素值与下三角部分的M(j, i)相同,故应映射到下标为q的元素d[q]中(其中q=j(j-1)/2+(i-1) )。 有了k和q的计算公式,即可实现对称矩阵的压缩存储。
  要实现对称矩阵的压缩存储,只需要在上述下三角矩阵的压缩存储上稍作修改即可:

元素设置

void setElement(SymmetricMatrix *matrix, int row, int col, int value) {
    if (row < 0 || row >= matrix->size || col < 0 || col >= matrix->size) {
        printf("Error: Invalid row or column index.\n");
    } else {
        // 交换行和列的位置,确保 row <= col
        if (row > col) {
            int temp = row;
            row = col;
            col = temp;
        }

        int index = row * matrix->size + col - (row * (row + 1) / 2); // 计算压缩存储的索引
        matrix->elements[index] = value;
    }
}

  setElement 函数用于设置对称矩阵中指定位置的元素值。

  • 在设置元素之前,会进行一些边界检查,并通过交换行和列的位置,确保 row <= col。
  • 然后根据压缩存储的方式计算出对应位置在 elements 数组中的索引,并将值赋给该位置的元素。

元素获取

int getElement(SymmetricMatrix *matrix, int row, int col) {
    if (row < 0 || row >= matrix->size || col < 0 || col >= matrix->size) {
        printf("Error: Invalid row or column index.\n");
        return 0;
    } else {
        // 交换行和列的位置,确保 row <= col
        if (row > col) {
            int temp = row;
            row = col;
            col = temp;
        }

        int index = row * matrix->size + col - (row * (row + 1) / 2); // 计算压缩存储的索引
        return matrix->elements[index];
    }
}

  getElement 函数用于获取对称矩阵中指定位置的元素值。

  • 同样进行边界检查,并通过交换行和列的位置,确保 row <= col。
  • 然后根据压缩存储的方式计算出对应位置在 elements 数组中的索引,并返回相应位置的元素值。

主函数

int main() {
    SymmetricMatrix matrix;
    int size = 4;  // 假设对称矩阵的维度为4

    initialize(&matrix, size);

    // 设置对称矩阵的元素值
    setElement(&matrix, 0, 0, 1);
    setElement(&matrix, 1, 1, 2);
    setElement(&matrix, 2, 2, 3);
    setElement(&matrix, 1, 0, 4);
    setElement(&matrix, 2, 0, 5);
    setElement(&matrix, 2, 1, 6);

    // 打印对称矩阵
    printMatrix(&matrix);

    return 0;
}

输出结果

在这里插入图片描述

代码整合

#include <stdio.h>

#define MAX_SIZE 100

// 定义对称矩阵结构体
typedef struct {
    int size;               // 矩阵的维度
    int elements[MAX_SIZE]; // 存储对称矩阵元素的数组
} SymmetricMatrix;

// 初始化对称矩阵
void initialize(SymmetricMatrix *matrix, int size) {
    matrix->size = size;

    // 初始化对称矩阵元素数组
    for (int i = 0; i < size * (size + 1) / 2; i++) {
        matrix->elements[i] = 0;
    }
}

// 设置对称矩阵中指定位置的元素值
void setElement(SymmetricMatrix *matrix, int row, int col, int value) {
    if (row < 0 || row >= matrix->size || col < 0 || col >= matrix->size) {
        printf("Error: Invalid row or column index.\n");
    } else {
        // 交换行和列的位置,确保 row <= col
        if (row > col) {
            int temp = row;
            row = col;
            col = temp;
        }

        int index = row * matrix->size + col - (row * (row + 1) / 2); // 计算压缩存储的索引
        matrix->elements[index] = value;
    }
}

// 获取对称矩阵中指定位置的元素值
int getElement(SymmetricMatrix *matrix, int row, int col) {
    if (row < 0 || row >= matrix->size || col < 0 || col >= matrix->size) {
        printf("Error: Invalid row or column index.\n");
        return 0;
    } else {
        // 交换行和列的位置,确保 row <= col
        if (row > col) {
            int temp = row;
            row = col;
            col = temp;
        }

        int index = row * matrix->size + col - (row * (row + 1) / 2); // 计算压缩存储的索引
        return matrix->elements[index];
    }
}

// 打印对称矩阵
void printMatrix(SymmetricMatrix *matrix) {
    for (int i = 0; i < matrix->size; i++) {
        for (int j = 0; j < matrix->size; j++) {
            printf("%d ", getElement(matrix, i, j));
        }
        printf("\n");
    }
}

int main() {
    SymmetricMatrix matrix;
    int size = 4;  // 假设对称矩阵的维度为3

    initialize(&matrix, size);

    // 设置对称矩阵的元素值
    setElement(&matrix, 0, 0, 1);
    setElement(&matrix, 1, 1, 2);
    setElement(&matrix, 2, 2, 3);
    setElement(&matrix, 1, 0, 4);
    setElement(&matrix, 2, 0, 5);
    setElement(&matrix, 2, 1, 6);

    // 打印对称矩阵
    printMatrix(&matrix);

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1132711.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

图像数据噪音种类以及Python生成对应噪音

前言 当涉及到图像处理和计算机视觉任务时&#xff0c;噪音是一个不可忽视的因素。噪音可以由多种因素引起&#xff0c;如传感器误差、通信干扰、环境光线变化等。这些噪音会导致图像质量下降&#xff0c;从而影响到后续的图像分析和处理过程。因此&#xff0c;对于从图像中获…

Thread同步问题,小案例

要求 有两个用户分别从同一个卡上取钱(总额&#xff1a;10000元)每次都取1000&#xff0c;当余额不足时&#xff0c;就不能取款了不能出现超取现象> 线程同步问题 public static void main(String[] args) {BankChoic bankChoic new BankChoic();Thread thread1 new Th…

设计一个高效算法,将顺序表L的所有元素逆置,要求算法的空间复杂度为O(1)

初始化及打印函数 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #define MaxSize 10//定义最大长度 int InitArr[10] { 1,2,3,4,5,6,7,8,9,10 };typedef struct {int data[MaxSize];//用静态的数据存放数据元素int length;//顺序表当前长度 }Sqlist;//顺序表的类…

苹果将于8月31日举行今秋的第二场发布会

在今日凌晨&#xff0c;苹果宣布&#xff0c;将于北京时间10月31日早上8点举行今秋的第二场发布会&#xff0c;主题为“来势迅猛”。据多方猜测苹果本次活动的核心产品大概率是搭载全新M3芯片的Mac系列产品。 据了解&#xff0c;在苹果的产品线中&#xff0c;搭载M3芯片的Mac系…

C++ BinarySercahTree recursion version

for循环版本的&#xff1a;C BinarySercahTree for version-CSDN博客 Inorder()在c BinarySerschTree for verison写了。 还是按照那种嵌套的方式来写递归。 现在来写查找 FindR() bool FindR(){return _FindR(_root);}然后_FindR()函数写递归具体实现&#xff1a; 假设要…

HAL库 CubeMX STM32采用SDIO实现对SD卡和NAND Flash的读写

目录 一、选择合适的存储芯片。 可以去雷龙官网白嫖&#xff0c;白嫖链接&#xff1a;免费样品 二、SD卡/SD NAND底层原理 三、 CubeMX配置STM32具体步骤 1、时钟和系统配置 2、配置SDIO 3、配置DMA &#xff08;可选&#xff09; 4、设置串口 四、代码编写 1、公共…

vue 数据劫持代理原理

function lianxi(){// vue 数据劫持代理let data {username:curry,age:33}//模拟组件的实例let _this {}//利用Object.defineProperty()for( let item in data){//console.log(item,data[item])Object.defineProperty(_this,item,{//get:用来获取扩展属性值的,当获取该属性值…

基本指令(2):通配符,重定向,命令行管道

一、通配符 rm -rf ./* # * —— 通配符&#xff0c;指定路径下的所有文件&#xff08;不包括隐藏文件&#xff09;二、重定向 在理解重定向前&#xff0c;先要有一个概念&#xff1a;Linux下一切皆文件&#xff0c;大部分硬件设备都可以看做有读写方法&#xff0c;只不过有些方…

Web前端免费接入Microsoft Azure AI文本翻译,享每月2百万个字符的翻译

Azure 文本翻译是 Azure AI 翻译服务的一项基于云的 REST API 功能。 文本翻译 API 支持实时快速准确地进行源到目标文本翻译。 文本翻译软件开发工具包 (SDK) 是一组库和工具&#xff0c;可用于轻松地将文本翻译 REST API 功能集成到应用程序中。 文本翻译 SDK 可跨 C#/.NET、…

国腾GM8775C完全替代CS5518 MIPIDSI转2 PORT LVDS

集睿致远CS5518描述&#xff1a; CS5518是一款MIPI DSI输入、LVDS输出转换芯片。MIPI DSI 支持多达4个局域网&#xff0c;每条通道以最 大 1Gbps 的速度运行。LVDS支持18位或24位像素&#xff0c;25Mhz至154Mhz&#xff0c;采用VESA或JEIDA格 式。它只能使用单个1.8v电源&am…

人脸活体检测:Domain-Generalized Face Anti-Spoofing with Unknown Attacks

论文作者&#xff1a;Zong-Wei Hong,Yu-Chen Lin,Hsuan-Tung Liu,Yi-Ren Yeh,Chu-Song Chen 作者单位&#xff1a;National Taiwan University; E.SUN Financial Holding Co., Ltd.; National Kaohsiung Normal University 论文链接&#xff1a;http://arxiv.org/abs/2310.11…

Echarts多曲线数值与Y周刻度不符合

发现问题&#xff1a; 在展示多曲线图表的时候&#xff0c;发现图表曲线数值相差不大&#xff0c;但是图表展示的曲线相差很大&#xff0c;仔细观察之后发现是展示有问题(其实这并不能算是错误&#xff0c;只是由于忽略&#xff0c;导致的配置与预期不符合)。 问题复现&#x…

【低代码平台】JeecgBoot代码生成器如何使用?Online代码生成

Online代码生成 目前Vue3已经支持两种模式&#xff1a;Online在线模式 和 GUI模式代码生成。 JeecgBoot版本要求&#xff1a; 3.2.0 ( 提供了vue3、vue3Native模板目录 ) 第一步&#xff1a;通过online表单在线建表 jeecg提供了在线建表的功能&#xff0c;找到菜单&#xff1a;…

关于城市综合管廊分析与应用

安科瑞 华楠 摘要&#xff1a;文章介绍了城市综合管廊的概念和我国综合管廊建设的背景&#xff0c;并总结归纳了综合管廊的设计要点以及注意事项&#xff0c;为今后的综合管廊设计提供参考。 关键词&#xff1a;城市&#xff1b;综合管廊&#xff1b;应用 1 规划背景及技术路…

GEE案例——一个完整的火灾监测案例dNBR差异化归一化烧毁指数

差异化归一化烧毁指数 dNBR是"差异化归一化烧毁指数"的缩写。它是一种用于评估卫星图像中烧毁区域严重程度的遥感指数。dNBR值通过将火灾前的归一化烧毁指数(NBR)减去火灾后的NBR来计算得出。该指数常用于野火监测和评估。 dNBR(差异化归一化烧毁指数)是一种用…

报错:Could not resolve host: mirrorlist.centos.org;Unknown error

报错&#xff1a;Could not resolve host: mirrorlist.centos.org;Unknown error 一般是因为网络配置错误导致无法连接外网&#xff0c;我们先尝试ping一下www.baidu.com发现无法ping通。 果然&#xff0c;接下来我们就开始排查吧&#xff01;&#xff01; 1.网络配置查看 打开…

LeetCode88——合并两个有序数组

LeetCode88——合并两个有序数组 1.题目描述&#xff1a; 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中&#xff0c;使合并后的数组同样按 非递减…

SylixOS BSP开发(八)

初始化FPU、MMU和Cache组件 本来想在不初始化这些部件的情况下把SylixOS先启动起来感受下&#xff0c;结果测试发现如果MMU不使能的话&#xff0c;系统启动过程中线程无法进行调度emm。。。所以只好把这一章节提前来讲了。这三个组件的初始化都是在bspInit.c中进行的。 1. FPU初…

从零开始做一个SDWAN

VPN和SD-WAN的区别 VPN&#xff08;Virtual Private Network&#xff09;和SD-WAN&#xff08;Software-Defined Wide Area Network&#xff09;是两种不同的网络技术&#xff0c;它们在目的、功能和实施方式上有一些重要的区别。 目的和应用场景: VPN&#xff1a;VPN主要用于…

做图标设计一些常用的设计规范分享

应用程序图标设计是将某个概念转换为清晰易读的图形&#xff0c;从而降低用户的理解成本&#xff0c;提高界面的美感。在我们的企业级应用设计范围内&#xff0c;应用图标在界面设计的许多元素中往往只占很小的比例&#xff0c;调用时会缩小到比设计稿小很多倍的尺寸。此外&…