【数据结构】数组和字符串(六):特殊矩阵的压缩存储:稀疏矩阵——压缩稀疏列(Compressed Sparse Column,CSC)

news2024/11/16 7:24:16

文章目录

  • 4.2.1 矩阵的数组表示
  • 4.2.2 特殊矩阵的压缩存储
    • a. 对角矩阵的压缩存储
    • b~c. 三角、对称矩阵的压缩存储
    • d. 稀疏矩阵的压缩存储——三元组表
    • e. 压缩稀疏行(Compressed Sparse Row,CSR)矩阵
    • f. 压缩稀疏列(Compressed Sparse Column,CSC)矩阵
      • 结构体
      • 创建CSC矩阵
      • 元素设置
      • 初始化
      • 打印矩阵
      • 销毁CSC矩阵
      • 主函数
      • 代码整合

4.2.1 矩阵的数组表示

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

4.2.2 特殊矩阵的压缩存储

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

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

a. 对角矩阵的压缩存储

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

b~c. 三角、对称矩阵的压缩存储

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

d. 稀疏矩阵的压缩存储——三元组表

【数据结构】数组和字符串(四):特殊矩阵的压缩存储:稀疏矩阵——三元组表

e. 压缩稀疏行(Compressed Sparse Row,CSR)矩阵

【数据结构】数组和字符串(五):特殊矩阵的压缩存储:稀疏矩阵——压缩稀疏行(CSR)

f. 压缩稀疏列(Compressed Sparse Column,CSC)矩阵

  压缩稀疏列(Compressed Sparse Column,CSC)以列为主要组织方式,将矩阵按列进行存储。它包含三个主要数组:

  1. 列指针数组(Column Pointer Array):该数组的长度为矩阵的列数加一(cols+1),每个元素存储对应列中第一个非零元素在元素数组中的索引位置。最后一个元素存储非零元素的总数以及元素数组的长度。

  2. 行索引数组(Row Index Array):该数组的长度等于非零元素的数量,每个元素存储对应非零元素所在的行索引。

  3. 元素数组(Element Array):该数组的长度等于非零元素的数量,每个元素存储非零元素的值以及它所在的列索引。

  通过这种方式,CSC格式将稀疏矩阵的非零元素按列进行存储,并通过列指针数组和行索引数组提供了对非零元素在矩阵中位置的快速访问。

结构体

typedef struct {
    int row;
    int col;
    int value;
} Element;

typedef struct {
    int rows;
    int cols;
    int num_elements;
    Element* elements;
    int* col_ptr;
    int* row_indices;
} CSCMatrix;
  • Element 结构体表示矩阵中的一个元素,包含三个成员变量:row(行索引)、col(列索引)和 value(元素值)。

  • CSCMatrix 结构体表示一个CSC矩阵,包含了矩阵的行数 rows、列数 cols、非零元素的个数 num_elements,以及三个指针成员变量 elementscol_ptrrow_indices

创建CSC矩阵

CSCMatrix createCSCMatrix(int rows, int cols, int num_elements) {
    CSCMatrix matrix;
    matrix.rows = rows;
    matrix.cols = cols;
    matrix.num_elements = num_elements;
    matrix.elements = (Element*)malloc(num_elements * sizeof(Element));
    matrix.col_ptr = (int*)malloc((cols + 1) * sizeof(int));
    matrix.row_indices = (int*)malloc(num_elements * sizeof(int));

    memset(matrix.col_ptr, 0, (cols + 1) * sizeof(int));

    return matrix;
}
  • createCSCMatrix 函数用于创建一个CSC矩阵。
  • 接受矩阵的行数、列数和非零元素的个数作为参数,并返回创建的CSC矩阵。
  • 在函数内部,通过动态内存分配分别为 elementscol_ptrrow_indices 分配内存空间,并将 col_ptr 数组的所有元素初始化为0,最后返回创建的矩阵。

元素设置

void setElement(CSCMatrix* matrix, int row, int col, int value) {
    if (col < 0 || col >= matrix->cols) {
        printf("Invalid column index.\n");
        return;
    }

    int index = matrix->col_ptr[col];
    matrix->elements[index].row = row;
    matrix->elements[index].col = col;
    matrix->elements[index].value = value;
    matrix->row_indices[index] = row;
    matrix->col_ptr[col]++;  // 递增索引值
}

  setElement 函数可用于设置(修改)CSC矩阵中某个位置的元素值。

  • 接受一个指向CSC矩阵的指针 matrix,以及要设置的元素的行索引、列索引和值作为参数。
  • 在函数内部,首先检查列索引是否有效,如果无效则打印错误信息并返回。
  • 然后,根据列索引找到对应列的起始位置,将元素的行索引、列索引和值分别赋给对应的矩阵元素,并更新 row_indices 数组和 col_ptr 数组中的值。

初始化


void initializeCSCMatrix(CSCMatrix* matrix, int* values, int* row_indices, int* col_indices, int num_elements) {
    for (int i = 0; i < num_elements; i++) {
        matrix->elements[i].value = values[i];
        matrix->elements[i].row = row_indices[i];
        matrix->elements[i].col = col_indices[i];
        matrix->row_indices[i] = row_indices[i];
        matrix->col_ptr[col_indices[i]]++;
    }

    int sum = 0;
    for (int i = 0; i <= matrix->cols; i++) {
        int temp = matrix->col_ptr[i];
        matrix->col_ptr[i] = sum;
        sum += temp;
    }
}

  initializeCSCMatrix 函数用于初始化CSC矩阵的数据。

  • 接受一个指向CSC矩阵的指针 matrix,以及包含非零元素的值、行索引和列索引的数组,以及非零元素的个数作为参数。
  • 通过遍历非零元素数组,将值、行索引和列索引分别赋给对应的矩阵元素,并更新 row_indices 数组和 col_ptr 数组中的值。col_ptr 数组的每个元素表示对应列的非零元素在 elements 数组中的起始位置,通过累加非零元素的个数来计算每列的结束位置。

打印矩阵

void printCSCMatrix(CSCMatrix matrix) {
    printf("CSC Matrix:\n");
    printf("Rows: %d, Cols: %d, Num Elements: %d\n", matrix.rows, matrix.cols, matrix.num_elements);
    printf("Values: ");
    for (int i = 0; i < matrix.num_elements; i++) {
        printf("%d ", matrix.elements[i].value);
    }
    printf("\n");
    printf("Column Pointer: ");
    for (int i = 0; i <= matrix.cols; i++) {
        printf("%d ", matrix.col_ptr[i]);
    }
    printf("\n");
    printf("Row Indices: ");
    for (int i = 0; i < matrix.num_elements; i++) {
        printf("%d ", matrix.row_indices[i]);
    }
    printf("\n");
}

void printMatrixForm(CSCMatrix matrix) {
    printf("Matrix Form:\n");
    for (int i = 0; i < matrix.rows; i++) {
        for (int j = 0; j < matrix.cols; j++) {
            int value = 0;
            for (int k = matrix.col_ptr[j]; k < matrix.col_ptr[j + 1]; k++) {
                if (matrix.elements[k].row == i) {
                    value = matrix.elements[k].value;
                    break;
                }
            }
            printf("%d ", value);
        }
        printf("\n");
    }
}
  • printCSCMatrix 函数用于打印CSC矩阵的信息:它接受一个CSC矩阵作为参数,并打印矩阵的行数、列数、非零元素的个数以及 elementscol_ptrrow_indices 数组的内容。
  • printMatrixForm 函数用于以矩阵形式打印CSC矩阵。它接受一个CSC矩阵作为参数,并按矩阵的行数和列数遍历矩阵元素,通过遍历 col_ptr 数组和 row_indices 数组来获取每个位置的元素值,并打印出矩阵的形式。

销毁CSC矩阵

void destroyCSCMatrix(CSCMatrix* matrix) {
    free(matrix->elements);
    free(matrix->col_ptr);
    free(matrix->row_indices);
    matrix->elements = NULL;
    matrix->col_ptr = NULL;
    matrix->row_indices = NULL;
}

主函数


int main() {
    int rows = 3;
    int cols = 9;
    int num_elements = 5;

    CSCMatrix matrix = createCSCMatrix(rows, cols, num_elements);

    int row_indices[] = {0, 0, 0, 0, 1};
    int col_indices[] = {3, 5, 7, 8, 7};
    int values[] =      {2, 1, 3, 1, 4};

    initializeCSCMatrix(&matrix, values, row_indices, col_indices, num_elements);

    printCSCMatrix(matrix);
    printMatrixForm(matrix);

    destroyCSCMatrix(&matrix);
    return 0;
}

在这里插入图片描述

代码整合

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

typedef struct {
    int row;
    int col;
    int value;
} Element;

typedef struct {
    int rows;
    int cols;
    int num_elements;
    Element* elements;
    int* col_ptr;
    int* row_indices;
} CSCMatrix;

CSCMatrix createCSCMatrix(int rows, int cols, int num_elements) {
    CSCMatrix matrix;
    matrix.rows = rows;
    matrix.cols = cols;
    matrix.num_elements = num_elements;
    matrix.elements = (Element*)malloc(num_elements * sizeof(Element));
    matrix.col_ptr = (int*)malloc((cols + 1) * sizeof(int));
    matrix.row_indices = (int*)malloc(num_elements * sizeof(int));

    memset(matrix.col_ptr, 0, (cols + 1) * sizeof(int));

    return matrix;
}

void setElement(CSCMatrix* matrix, int row, int col, int value) {
    if (col < 0 || col >= matrix->cols) {
        printf("Invalid column index.\n");
        return;
    }

    int index = matrix->col_ptr[col];
    matrix->elements[index].row = row;
    matrix->elements[index].col = col;
    matrix->elements[index].value = value;
    matrix->row_indices[index] = row;
    matrix->col_ptr[col]++;  // 递增索引值
}

void printCSCMatrix(CSCMatrix matrix) {
    printf("CSC Matrix:\n");
    printf("Rows: %d, Cols: %d, Num Elements: %d\n", matrix.rows, matrix.cols, matrix.num_elements);
    printf("Values: ");
    for (int i = 0; i < matrix.num_elements; i++) {
        printf("%d ", matrix.elements[i].value);
    }
    printf("\n");
    printf("Column Pointer: ");
    for (int i = 0; i <= matrix.cols; i++) {
        printf("%d ", matrix.col_ptr[i]);
    }
    printf("\n");
    printf("Row Indices: ");
    for (int i = 0; i < matrix.num_elements; i++) {
        printf("%d ", matrix.row_indices[i]);
    }
    printf("\n");
}

void printMatrixForm(CSCMatrix matrix) {
    printf("Matrix Form:\n");
    for (int i = 0; i < matrix.rows; i++) {
        for (int j = 0; j < matrix.cols; j++) {
            int value = 0;
            for (int k = matrix.col_ptr[j]; k < matrix.col_ptr[j + 1]; k++) {
                if (matrix.elements[k].row == i) {
                    value = matrix.elements[k].value;
                    break;
                }
            }
            printf("%d ", value);
        }
        printf("\n");
    }
}

void destroyCSCMatrix(CSCMatrix* matrix) {
    free(matrix->elements);
    free(matrix->col_ptr);
    free(matrix->row_indices);
    matrix->elements = NULL;
    matrix->col_ptr = NULL;
    matrix->row_indices = NULL;
}

void initializeCSCMatrix(CSCMatrix* matrix, int* values, int* row_indices, int* col_indices, int num_elements) {
    for (int i = 0; i < num_elements; i++) {
        matrix->elements[i].value = values[i];
        matrix->elements[i].row = row_indices[i];
        matrix->elements[i].col = col_indices[i];
        matrix->row_indices[i] = row_indices[i];
        matrix->col_ptr[col_indices[i]]++;
    }

    int sum = 0;
    for (int i = 0; i <= matrix->cols; i++) {
        int temp = matrix->col_ptr[i];
        matrix->col_ptr[i] = sum;
        sum += temp;
    }
}

int main() {
    int rows = 3;
    int cols = 9;
    int num_elements = 5;

    CSCMatrix matrix = createCSCMatrix(rows, cols, num_elements);

    int row_indices[] = {0, 0, 0, 0, 1};
    int col_indices[] = {3, 5, 7, 8, 7};
    int values[] =      {2, 1, 3, 1, 4};

    initializeCSCMatrix(&matrix, values, row_indices, col_indices, num_elements);

    printCSCMatrix(matrix);
    printMatrixForm(matrix);

    destroyCSCMatrix(&matrix);
    return 0;
}

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

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

相关文章

【计算机毕设小程序案例】基于微信小程序的图书馆座位预定系统

前言&#xff1a;我是IT源码社&#xff0c;从事计算机开发行业数年&#xff0c;专注Java领域&#xff0c;专业提供程序设计开发、源码分享、技术指导讲解、定制和毕业设计服务 &#x1f449;IT源码社-SpringBoot优质案例推荐&#x1f448; &#x1f449;IT源码社-小程序优质案例…

Android拖放startDragAndDrop拖拽onDrawShadow动态添加View,Kotlin(3)

Android拖放startDragAndDrop拖拽onDrawShadow动态添加View&#xff0c;Kotlin&#xff08;3&#xff09; import android.content.ClipData import android.graphics.Canvas import android.graphics.Point import android.os.Bundle import android.util.Log import android.…

【linux】麒麟v10安装Redis主从集群(ARM架构)

安装redis单示例的请看&#xff1a;麒麟v10安装Redis&#xff08;ARM架构&#xff09; 安装环境 ​Hostname​IP addressmaster192.168.0.1slave1192.168.0.2slave2192.168.0.3 下载安装包 &#xff08;三台都操作&#xff09; wget https://repo.huaweicloud.com/kunpeng/…

iStat Menus v6.72

iStat Menus是一款Mac电脑上的系统监控工具&#xff0c;它可以帮助用户监测电脑的硬件和软件状况&#xff0c;提供实时的系统数据和统计信息。 其主要特点包括&#xff1a; 1.系统监测&#xff1a;iStat Menus可以监测CPU、内存、硬盘、网络、电池等系统参数&#xff0c;方便…

SLAM从入门到精通(lidar的运动畸变矫正)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们说过&#xff0c;很多时候传感器的数据并不能直接拿过来使用。这里面除了噪声的原因之外&#xff0c;另外一部分原因就是传感器数据本身也…

Linux 多架构支持介绍和实践

Linux 多架构支持介绍和实践 1. Linux 上多架构支持指的是什么意思&#xff1f; 在Linux 上开启多架构支持&#xff08;multi-arch support&#xff09;&#xff0c;指的是可以让您在同一系统上安装多个不同架构的软件包&#xff0c;这在交叉编译的场景显得格外重要。 以下实…

分享一下怎么做一个微信抽奖活动

抽奖活动是当今社会中非常流行的一种营销方式&#xff0c;它能够有效地吸引消费者的注意力&#xff0c;提高品牌知名度和销售额。在举办抽奖活动时&#xff0c;需要制定相应的规则和奖励设置&#xff0c;以确保活动的公平性和吸引力。本文将详细介绍如何制作一个有效的抽奖活动…

外汇天眼:如何有效地交易外汇?15个基本提示!

外汇是买卖货币的行为。日均交易量超过6万亿美元&#xff0c;是世界上最大的金融市场。鉴于其规模和可及性&#xff0c;许多人被高回报的承诺所吸引。但是&#xff0c;如果没有适当的知识和纪律&#xff0c;交易可能会有风险。在本文中&#xff0c;很好地分解了有效交易外汇的基…

2023高频前端面试题-浏览器

1. 浏览器是如何解析 CSS 选择器的&#xff1f; 在生成渲染树的过程中&#xff0c;渲染引擎会根据选择器提供的信息来遍历 DOM 树&#xff0c;找到对应的 DOM 节点后将样式规则附加到上面。 来看一段样式选择器代码、以及一段要应用样式的 HTML&#xff1a; .mod-nav h3 spa…

AI口语APP第三方接口

AI口语练习应用程序通常可以通过第三方接口来集成语音识别、自然语言处理和其他相关功能。以下是一些常见的第三方接口及其特点&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1.Google Cloud Speech…

如何设计元宇宙展厅,元宇宙展厅的展示和交互形式有哪些?

引言&#xff1a; 元宇宙是当下科技界最为炙手可热的话题之一&#xff0c;被誉为数字世界的未来。将元宇宙与展厅结合&#xff0c;展示产品信息成了很多人关注的热点&#xff0c;那么元宇宙展厅应该如何设计呢&#xff1f; 一&#xff0e;元宇宙展厅设计理念 1.创造虚拟与现实…

为什么选择Codigger静态分析?

开发每个阶段的安全代码 Codigger是一种很流行的静态分析工具&#xff0c;用于持续检查代码库的代码质量和安全性&#xff0c;并在代码评审期间指导开发团队。代码审查是一种系统的软件质量保证技术&#xff0c;通过审查开发人员的代码来发现和修复问题、提高代码质量并执行编码…

九月手游出海三黑马,营销上如何做到成功?

从2022年开始&#xff0c;手游出海红利几乎完全消失&#xff0c;在经历高速发展的黄金阶段过渡到竞争激烈的精品化阶段&#xff0c;再到目前“不上不下”的存量竞争时代。 现在手游出海到底面临怎么样的困境&#xff1f;是全球经济下行、隐私政策更新频繁、国际形势变化莫测、…

【工具使用】使用Audition增加增益的方法

一&#xff0c;简介 本文主要介绍如何在Adobe Audition 2020中改变波形的幅值。供参考。 二&#xff0c;操作方法 这里使用1KHz&#xff0c;-120dB信号为例。 2.1 方法一&#xff1a;直接使用悬浮窗口 窗口中输入6&#xff0c;波形的幅值就变成了-114dB。 注意&#xff1a…

ChatGLM系列五:Lora微调

目前主流对大模型进行微调方法有三种&#xff1a;Freeze方法、P-Tuning方法和Lora方法 LoRA: 在大型语言模型上对指定参数&#xff08;权重矩阵&#xff09;并行增加额外的低秩矩阵&#xff0c;并在模型训练过程中&#xff0c;仅训练额外增加的并行低秩矩阵的参数,冻结其他参数…

Java中级面试题记录(四)

一面面试题 1.Innodb的行数据存储模式 https://baijiahao.baidu.com/s?id1775090633458928876&wfrspider&forpc 2.行数据包含哪些信息&#xff1f; https://baijiahao.baidu.com/s?id1775090633458928876&wfrspider&forpc 3.MySQL在进行存储VARCHAR的时…

qq怎么发长视频?超级好用!

在平时的工作和生活中&#xff0c;我们会想分享一些比较长的内容。但是我们会发现视频文件过大&#xff0c;可能会超过腾讯规定的单次发送文件的大小限制&#xff0c;导致无法发送成功。这时候就需要借助一些视频压缩工具&#xff0c;下面介绍了四种方法&#xff0c;一起来看看…

浅谈信息化与数字化

一、信息化/数字化的概念 信息化、数字化按字面意思理解&#xff0c;这两个词的确代表了不同的含义。但是也不可否认&#xff0c;在目前我们可以接触到的信息平台来看。信息化、数字化很多时候都被混在一起了。 那么&#xff0c;既然今天要聊这个话题。我们得先把这两个词分清…

【C++】:拷贝构造函数与赋值运算符重载的实例应用之日期类的实现

C实现日期类 ├─属性&#xff1a; │ ├─年份 │ ├─月份 │ └─日期 ├─方法&#xff1a; │ ├─构造函数 │ ├─拷贝构造函数 │ ├─析构函数 │ ├─设置年份 │ ├─设置月份 │ ├─设置日期 │ ├─获取年份 │ ├─获取月份 │ ├─获取日期 │ ├…

mysql-linux归档版安装

什么是归档版安装&#xff1f;简单来说就是编译好的软件压缩打包版。 说明&#xff1a;我这里服务器之前已经装过一个不同版本的mysql&#xff0c;已经占用了3306端口&#xff0c;所以这里我用3307端口来演示&#xff0c;命令和官方的稍有不同&#xff0c;不过步骤都是差不多的…