多维数组与特殊矩阵:存储与压缩

多维数组与特殊矩阵:存储与压缩

一、多维数组的存储

(一)基本概念

多维数组是线性表的推广,例如二维数组可以看作是元素为一维数组的线性表,三维数组可以看作是元素为二维数组的线性表,以此类推。在内存中,多维数组需要按照一定的顺序进行存储,常见的存储方式有行优先存储和列优先存储。

(二)行优先存储

以二维数组为例,行优先存储是先存储第一行的元素,然后再存储第二行的元素,依此类推。对于一个 mn 列的二维数组 a[m][n],其元素 a[i][j] 在内存中的地址计算(假设每个元素占用 k 个字节,数组首地址为 base):
[LOC(a[i][j]) = base + (i * n + j) * k]

(三)列优先存储

列优先存储则是先存储第一列的元素,再存储第二列的元素等。对于上述二维数组,元素 a[i][j] 在列优先存储下的内存地址计算:
[LOC(a[i][j]) = base + (j * m + i) * k]

(四)C 语言示例

以下是一个在 C 语言中对二维数组进行初始化并计算其元素地址的示例:

#include <stdio.h>

// 假设元素为 int 类型,每个 int 占 4 个字节
#define ELEMENT_SIZE 4

// 计算行优先存储下元素的地址
int rowMajorAddress(int a[][100], int i, int j, int m, int n) {
    int base = (int)a;
    return base + (i * n + j) * ELEMENT_SIZE;
}

// 计算列优先存储下元素的地址
int colMajorAddress(int a[][100], int i, int j, int m, int n) {
    int base = (int)a;
    return base + (j * m + i) * ELEMENT_SIZE;
}

int main() {
    // 声明一个 3 行 4 列的二维数组并初始化
    int matrix[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };

    // 计算并打印行优先存储下元素 matrix[1][2] 的地址
    int rowAddr = rowMajorAddress(matrix, 1, 2, 3, 4);
    printf("行优先存储下 matrix[1][2] 的地址: %d\n", rowAddr);

    // 计算并打印列优先存储下元素 matrix[1][2] 的地址
    int colAddr = colMajorAddress(matrix, 1, 2, 3, 4);
    printf("列优先存储下 matrix[1][2] 的地址: %d\n", colAddr);

    return 0;
}

二、特殊矩阵的存储与压缩

(一)对称矩阵

  1. 存储特点
    • 对称矩阵是指 a[i][j] = a[j][i] 的矩阵。对于一个 n 阶对称矩阵,我们只需要存储其下三角(或上三角)部分的元素即可,因为根据对称性可以得到另一半元素的值。
  2. 存储方式
    • 可以将下三角部分按行优先存储到一个一维数组 sa 中。对于下三角元素 a[i][j]i >= j),其在一维数组中的下标 k 计算如下:
      [k=\frac{i(i + 1)}{2}+j]
  3. C 语言示例
// 存储对称矩阵的下三角部分到一维数组
void storeSymmetricMatrix(int a[][100], int sa[], int n) {
    int k = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j <= i; j++) {
            sa[k++] = a[i][j];
        }
    }
}

// 根据一维数组恢复对称矩阵
void restoreSymmetricMatrix(int a[][100], int sa[], int n) {
    int k = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j <= i; j++) {
            a[i][j] = sa[k];
            a[j][i] = sa[k++];
        }
    }
}

int main() {
    // 声明一个 4 阶对称矩阵并初始化
    int symmetricMatrix[4][4] = {
        {1, 2, 3, 4},
        {2, 5, 6, 7},
        {3, 6, 8, 9},
        {4, 7, 9, 10}
    };
    int sa[10];  // 用于存储对称矩阵下三角部分的一维数组

    // 存储对称矩阵下三角部分
    storeSymmetricMatrix(symmetricMatrix, sa, 4);

    // 恢复对称矩阵
    int restoredMatrix[4][4];
    restoreSymmetricMatrix(restoredMatrix, sa, 4);

    // 打印恢复后的对称矩阵,验证正确性
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%d ", restoredMatrix[i][j]);
        }
        printf("\n");
    }

    return 0;
}

(二)三角矩阵

  1. 上三角矩阵
    • 存储特点:上三角矩阵是主对角线以下元素全为 0 的矩阵。对于 n 阶上三角矩阵,我们可以只存储其主对角线及以上的元素。
    • 存储方式:按行优先存储主对角线及以上元素到一维数组 ua 中。对于上三角元素 a[i][j]i <= j),其在一维数组中的下标 k 计算如下:
      [k=\frac{(2n - i - 1)i}{2}+j - i]
    • C 语言示例
// 存储上三角矩阵到一维数组
void storeUpperTriangularMatrix(int a[][100], int ua[], int n) {
    int k = 0;
    for (int i = 0; i < n; i++) {
        for (int j = i; j < n; j++) {
            ua[k++] = a[i][j];
        }
    }
}

// 根据一维数组恢复上三角矩阵
void restoreUpperTriangularMatrix(int a[][100], int ua[], int n) {
    int k = 0;
    for (int i = 0; i < n; i++) {
        for (int j = i; j < n; j++) {
            a[i][j] = ua[k++];
            if (j > i) {
                a[j][i] = 0;
            }
        }
    }
}

int main() {
    // 声明一个 4 阶上三角矩阵并初始化
    int upperTriangularMatrix[4][4] = {
        {1, 2, 3, 4},
        {0, 5, 6, 7},
        {0, 0, 8, 9},
        {0, 0, 0, 10}
    };
    int ua[10];  // 用于存储上三角矩阵的一维数组

    // 存储上三角矩阵
    storeUpperTriangularMatrix(upperTriangularMatrix, ua, 4);

    // 恢复上三角矩阵
    int restoredUpperMatrix[4][4];
    restoreUpperTriangularMatrix(restoredUpperMatrix, ua, 4);

    // 打印恢复后的上三角矩阵,验证正确性
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%d ", restoredUpperMatrix[i][j]);
        }
        printf("\n");
    }

    return 0;
}
  1. 下三角矩阵
    • 存储特点:下三角矩阵是主对角线以上元素全为 0 的矩阵。
    • 存储方式:类似对称矩阵下三角存储,按行优先存储下三角元素到一维数组 la 中。对于下三角元素 a[i][j]i >= j),其在一维数组中的下标 k 计算同对称矩阵下三角元素存储下标计算:
      [k=\frac{i(i + 1)}{2}+j]
    • C 语言示例
// 存储下三角矩阵到一维数组
void storeLowerTriangularMatrix(int a[][100], int la[], int n) {
    int k = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j <= i; j++) {
            la[k++] = a[i][j];
        }
    }
}

// 根据一维数组恢复下三角矩阵
void restoreLowerTriangularMatrix(int a[][100], int la[], int n) {
    int k = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j <= i; j++) {
            a[i][j] = la[k++];
            if (j < i) {
                a[j][i] = 0;
            }
        }
    }
}

int main() {
    // 声明一个 4 阶下三角矩阵并初始化
    int lowerTriangularMatrix[4][4] = {
        {1, 0, 0, 0},
        {2, 5, 0, 0},
        {3, 6, 8, 0},
        {4, 7, 9, 10}
    };
    int la[10];  // 用于存储下三角矩阵的一维数组

    // 存储下三角矩阵
    storeLowerTriangularMatrix(lowerTriangularMatrix, la, 4);

    // 恢复下三角矩阵
    int restoredLowerMatrix[4][4];
    restoreLowerTriangularMatrix(restoredLowerMatrix, la, 4);

    // 打印恢复后的下三角矩阵,验证正确性
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%d ", restoredLowerMatrix[i][j]);
        }
        printf("\n");
    }

    return 0;
}

(三)对角矩阵

  1. 存储特点
    • 对角矩阵是指除主对角线及其相邻若干条对角线上的元素外,其余元素均为 0 的矩阵。以三对角矩阵为例,其主对角线以及主对角线上下各一条对角线上有非零元素。
  2. 存储方式
    • 可以将三对角矩阵的非零元素按行优先存储到一维数组 da 中。对于三对角矩阵中的元素 a[i][j],当 |i - j| <= 1 时为非零元素。其在一维数组中的下标 k 计算如下:
      [k = 3i - 1 + j - i = 2i + j - 1](当 (i = 0) 时,(k = j))
  3. C 语言示例
// 存储三对角矩阵到一维数组
void storeTriDiagonalMatrix(int a[][100], int da[], int n) {
    int k = 0;
    for (int i = 0; i < n; i++) {
        for (int j = i - 1; j <= i + 1; j++) {
            if (j >= 0 && j < n) {
                da[k++] = a[i][j];
            }
        }
    }
}

// 根据一维数组恢复三对角矩阵
void restoreTriDiagonalMatrix(int a[][100], int da[], int n) {
    int k = 0;
    for (int i = 0; i < n; i++) {
        for (int j = i - 1; j <= i + 1; j++) {
            if (j >= 0 && j < n) {
                a[i][j] = da[k++];
            } else {
                a[i][j] = 0;
            }
        }
    }
}

int main() {
    // 声明一个 5 阶三对角矩阵并初始化
    int triDiagonalMatrix[5][5] = {
        {1, 2, 0, 0, 0},
        {3, 4, 5, 0, 0},
        {0, 6, 7, 8, 0},
        {0, 0, 9, 10, 11},
        {0, 0, 0, 12, 13}
    };
    int da[14];  // 用于存储三对角矩阵的一维数组

    // 存储三对角矩阵
    storeTriDiagonalMatrix(triDiagonalMatrix, da, 5);

    // 恢复三对角矩阵
    int restoredTriMatrix[5][5];
    restoreTriDiagonalMatrix(restoredTriMatrix, da, 5);

    // 打印恢复后的三对角矩阵,验证正确性
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++) {
            printf("%d ", restoredTriMatrix[i][j]);
        }
        printf("\n");
    }

    return 0;
}

(四)稀疏矩阵

  1. 存储特点
    • 稀疏矩阵是指非零元素个数远小于矩阵元素总个数的矩阵。
  2. 存储方式 - 三元组顺序表
    • 可以使用三元组顺序表来存储稀疏矩阵。三元组顺序表包含三个一维数组,分别存储非零元素的行下标、列下标和值。
    • 首先定义三元组结构体:
typedef struct {
    int row;
    int col;
    int value;
} Triple;
  • 然后定义三元组顺序表结构体:
typedef struct {
    Triple data[100];
    int num;  // 非零元素个数
} SparseMatrix;
  • 存储稀疏矩阵到三元组顺序表的函数:
// 存储稀疏矩阵到三元组顺序表
void storeSparseMatrix(int a[][100], SparseMatrix *sm, int m, int n) {
    sm->num = 0;
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if (a[i][j]!= 0) {
                sm->data[sm->num].row = i;
                sm->data[sm->num].col = j;
                sm->data[sm->num].value = a[i][j];
                sm->num++;
            }
        }
    }
}
  • 根据三元组顺序表恢复稀疏矩阵的函数:
// 根据三元组顺序表恢复稀疏矩阵
void restoreSparseMatrix(int a[][100], SparseMatrix sm, int m, int n) {
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            a[i][j] = 0;
        }
    }
    for (int k = 0; k < sm.num; k++) {
        a[sm.data[k].row][sm.data[k].col] = sm.data[k].value;
    }
}
  • C 语言示例
int main() {
    // 声明一个稀疏矩阵并初始化
    int sparseMatrix[5][5] = {
        {0, 0, 3, 0, 0},
        {0, 0, 0, 0, 0},
        {0, 6, 0, 0, 0},
        {0, 0, 0, 0, 9},
        {0, 0, 0, 0, 0}
    };
    SparseMatrix sm;

    // 存储稀疏矩阵到三元组顺序表
    storeSparseMatrix(sparseMatrix, &sm, 5, 5);

    // 恢复稀疏矩阵
    int restoredSparseMatrix[5][5];
    restoreSparseMatrix(restoredSparseMatrix, sm, 5, 5);

    // 打印恢复后的稀疏矩阵,验证正确性
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++) {
            printf("%d ", restoredSparseMatrix[i][j]);
        }
        printf("\n");
    }

    return 0;
}

通过对多维数组和各种特殊矩阵的存储与压缩方式的深入理解和掌握,能够在处理大规模数据矩阵相关的问题时,有效地减少存储空间的占用并提高数据处理的效率。在实际应用中,例如在图像处理、科学计算(如有限元分析中的矩阵运算)、数据挖掘等领域,这些技术都有着广泛的应用前景。
在图像处理中,图像可以看作是一个二维矩阵,当处理一些具有特定对称性或稀疏性的图像数据时,利用相应的矩阵存储和压缩技术,可以减少内存的占用,加快图像的处理速度,如对一些纹理具有对称性的图像进行压缩存储以便后续的传输或分析。
在科学计算里,很多物理问题的数学模型最终会转化为大规模的矩阵运算。例如在结构力学的有限元分析中,得到的刚度矩阵往往是对称矩阵或稀疏矩阵,采用合适的存储方式能够显著降低存储需求,提高计算效率,使得在有限的计算机资源下能够处理更复杂的结构模型。
在数据挖掘领域,一些关联矩阵或相似度矩阵可能具有稀疏性的特点,运用稀疏矩阵的存储和处理方法,可以高效地挖掘数据之间的潜在关系,发现有价值的信息模式,如在社交网络分析中处理用户之间的关联矩阵,挖掘用户群体的特征和行为模式。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【案例学习】如何使用Minitab实现包装过程的自动化和改进

Masimo 是一家全球性的医疗技术公司&#xff0c;致力于开发和生产各种行业领先的监控技术&#xff0c;包括创新的测量、传感器和患者监护仪。在 Masimo Hospital Automation 平台的助力下&#xff0c;Masimo 的连接、自动化、远程医疗和远程监控解决方案正在改善医院内外的护理…

【JavaEE初阶】多线程初阶下部

文章目录 前言一、volatile关键字volatile 能保证内存可见性 二、wait 和 notify2.1 wait()方法2.2 notify()方法2.3 notifyAll()方法2.4 wait 和 sleep 的对比&#xff08;面试题&#xff09; 三、多线程案例单例模式 四、总结-保证线程安全的思路五、对比线程和进程总结 前言…

【小白学机器学习33】 大数定律python的 pandas.Dataframe 和 pandas.Series基础内容

目录 0 总结 0.1pd.Dataframe有一个比较麻烦琐碎的地方&#xff0c;就是引号 和括号 0.2 pd.Dataframe关于括号的原则 0.3 分清楚几个数据类型和对应的方法的范围 0.4 几个数据结构的构造关系 list → np.array(list) → pd.Series(np.array)/pd.Dataframe 1 python 里…

《用Python画蔡徐坤:艺术与编程的结合》

简介 大家好&#xff01;今天带来一篇有趣的Python编程项目&#xff0c;用代码画出知名偶像蔡徐坤的形象。这个项目使用了Python的turtle库&#xff0c;通过简单的几何图形和精心设计的代码来展示艺术与编程的结合。 以下是完整的代码和效果介绍&#xff0c;快来试试看吧&…

OSG开发笔记(三十三):同时观察物体不同角度的多视图从相机技术

​若该文为原创文章&#xff0c;未经允许不得转载 本文章博客地址&#xff1a;https://blog.csdn.net/qq21497936/article/details/143932273 各位读者&#xff0c;知识无穷而人力有穷&#xff0c;要么改需求&#xff0c;要么找专业人士&#xff0c;要么自己研究 长沙红胖子Qt…

数据结构(Java版)第二期:包装类和泛型

目录 一、包装类 1.1. 基本类型和对应的包装类 1.2. 装箱和拆箱 1.3. 自动装箱和自动拆箱 二、泛型的概念 三、引出泛型 3.1. 语法规则 3.2. 泛型的优点 四、类型擦除 4.1. 擦除的机制 五、泛型的上界 5.1. 泛型的上界的定义 5.2. 语法规则 六、泛型方法 6.1…

ffmpeg 视频滤镜:高斯模糊-gblur

滤镜描述 gblur 官网地址 > FFmpeg Filters Documentation 这个滤镜会将视频变得模糊。 滤镜使用 参数 gblur AVOptions:sigma <float> ..FV.....T. set sigma (from 0 to 1024) (default 0.5)steps <int> ..FV.....T…

vue中路由缓存

vue中路由缓存 问题描述及截图解决思路关键代码及打印信息截图 问题描述及截图 在使用某一平台时发现当列表页码切换后点击某一卡片进入详情页后&#xff0c;再返回列表页时页面刷新了。这样用户每次看完详情回到列表页都得再重新输入自己的查询条件&#xff0c;或者切换分页到…

eclipse-git项目提示NO-HEAD

1、出现该问题的过程 本人在用eclipse拉取git代码&#xff0c;刚拉取完&#xff0c;可能还没来得及跟本地的分支合并&#xff0c;电脑就卡动了。无奈只能重启电脑&#xff0c;打开eclipse&#xff0c;maven项目后面就出现了xxx NO-HEAD的提示。 2、问题解决 根据错误提示&am…

网络安全与加密

1.Base64简单说明描述&#xff1a;Base64可以成为密码学的基石&#xff0c;非常重要。特点&#xff1a;可以将任意的二进制数据进行Base64编码结果&#xff1a;所有的数据都能被编码为并只用65个字符就能表示的文本文件。65字符&#xff1a;A~Z a~z 0~9 / 对文件进行base64编码…

goframe开发一个企业网站 在vue-next-admin 显示验证码 19

index.go 文件中的代码&#xff0c;我将为该文件中的主要功能和方法添加注释&#xff0c;并生成一篇 Markdown 格式的文章。这将包括对每个函数的用途、输入参数和返回值的简要说明。 index.go 包和导入 package adminimport ("context""errors""gf…

数据库的联合查询

数据库的联合查询 简介为什么要使⽤联合查询多表联合查询时MYSQL内部是如何进⾏计算的构造练习案例数据案例&#xff1a;⼀个完整的联合查询的过程 内连接语法⽰例 外连接语法 ⽰例⾃连接应⽤场景示例表连接练习 ⼦查询语法单⾏⼦查询多⾏⼦查询多列⼦查询在from⼦句中使⽤⼦查…

Oracle 23ai 对应windows版本安装配置PLSQL导入pde文件navicat连接Oracle

因为有一个pde文件需要查看里面的数据&#xff0c;所以这次需要配置本地oracle数据库&#xff0c;并且导入数据&#xff0c;因为还有navicat&#xff0c;所以就想用navicat去连接查看。 1、找到官网。 Get Started with Oracle Database 23ai | Oracle 2、下载windows版本。…

Juc01_多线程概述、四种实现方式、常用方法API、生命周期、买票案例、synchronized锁

目录 本章讲述内容&#xff1a;多线程概述、四种实现方式、常用方法API、生命周期、买票案例、synchronized锁 ①. 多线程的概述 ②. 多线程的实现方式 ①. 继承Thread ②. 实现Runnable接口 ③. Callable接口(创建线程) ④. 线程池 ③. 设置和获取线程名称 ④. 线程…

一个高度可扩展的 Golang ORM 库【GORM】

GORM 是一个功能强大的 Golang 对象关系映射&#xff08;ORM&#xff09;库&#xff0c;它提供了简洁的接口和全面的功能&#xff0c;帮助开发者更方便地操作数据库。 1. 完整的 ORM 功能 • 支持常见的关系模型&#xff1a; • Has One&#xff08;一对一&#xff09; • …

ubuntu24挂载硬盘记录

1、显示硬盘及所属分区情况。在终端窗口中输入如下命令&#xff1a; sudo fdisk -l 找到自己硬盘的分区 我的地址/dev/sda 2、显示硬盘及所属分区情况。在终端窗口中输入如下命令&#xff0c;格式化自己硬盘&#xff1a; sudo mkfs -t ext4 /dev/sda 3、在终端窗口中输入如下…

Flink四大基石之Window

为什么要用WIndow 在流处理应用中&#xff0c;数据是连续不断的&#xff0c;有时我们需要做一些聚合类的处理&#xff0c;例如&#xff1a;在过去的1分钟内有多少用户点击了我们的网页。 在这种情况下&#xff0c;我们必须定义一个窗口(window)&#xff0c;用来收集最近1分钟内…

使用ENSP实现默认路由

一、项目拓扑 二、项目实现 1.路由器AR1配置 进入系统试图 sys将路由器命名为R1 sysname R1关闭信息中心 undo info-center enable 进入g0/0/0接口 int g0/0/0将g0/0/0接口IP地址配置为2.2.2.1/24 ip address 2.2.2.1 24进入g0/0/1接口 int g0/0/1将g0/0/1接口IP地址配置为1.…

《基于FPGA的便携式PWM方波信号发生器》论文分析(三)——数码管稳定显示与系统调试

一、论文概述 基于FPGA的便携式PWM方波信号发生器是一篇由任青颖、庹忠曜、黄洵桢、李智禺和张贤宇 等人发表的一篇期刊论文。该论文主要研究了一种新型的信号发生器&#xff0c;旨在解决传统PWM信号发生器在移动设备信号调控中存在的精准度低和便携性差的问题 。其基于现场可编…

vue 预览pdf 【@sunsetglow/vue-pdf-viewer】开箱即用,无需开发

sunsetglow/vue-pdf-viewer 开箱即用的pdf插件sunsetglow/vue-pdf-viewer, vue3 版本 无需多余开发&#xff0c;操作简单&#xff0c;支持大文件 pdf 滚动加载&#xff0c;缩放&#xff0c;左侧导航&#xff0c;下载&#xff0c;页码&#xff0c;打印&#xff0c;文本复制&…