一、数组的定义:数组是n(n>=1)个相同数据类型的数据元素构成的占用一块地址连续的内存单元的有限集合。所有的线性结构(包括线性表、堆栈、队列、串、数组和矩阵)的顺序存储结构实际上就是使用数组来存储。可见,数组是其他数据结构实现存续存储结构的基础,数组这种数据结构是软件设计中最基础的数据结构。

  二、数组的实现机制:数组通常以字节为计数单位,同时根据内存单元地址映像公式来分配内存。用高级语言定义数组时,数组在内存中的首地址由系统动态分配并保存。高级语言通常用数组名保存在内存中的首地址。一旦确定了一个数组的首地址,系统就可计算出该数组中任意一个数组元素的内存地址。由于计算数组各个元素内存地址的时间相等,所以存取数组中任意一个元素的时间也相等,通常称具有这种特性的存储结构为随机存储结构。所以说数组具有随机存储结构的特性。

  三、在数值分析中,常常会出现一些拥有许多相同数据元素或零元素的高阶矩阵。将具有许多相同元素或者零元素,且数据分布具有一定规律的矩阵称为特殊矩阵,例如,对称矩阵、三角矩阵和对角矩阵。为了节省存储空间,需要对这类矩阵进行压缩存储。压缩存储的原则是:多个值相同的矩阵元素分配同一个存储空间,零元素不分配存储空间。对于对称矩阵、三角矩阵和对角矩阵来说,首先根据矩阵中任意一个元素与压缩后一位数组的下标的对应关系得到每一个数据元素在数组中存储的位置,然后把非零的数据元素存放到一位数组中。

  四、称具有较多零元素且非零元素的分布无规律的矩阵为稀疏矩阵。由于稀疏矩阵中非零元素的分布无规律,因此,不能像特殊矩阵那样只存放非零元素值。稀疏矩阵的两种常用的存储结构是三元组表存储和十字链表存储。

  1.稀疏矩阵的三元组表存储。

  (1)对于稀疏矩阵中任意一个非零元素,除了存放非零元素的值(value)外,还需要同时存储它所在的行(row)、列(column)的位置;反之,用一个三元组(row,column,value)可以唯一确定一个非零元素。由此,稀疏矩阵可由表示非零元的三元组及其行列式唯一确定。

  (2)稀疏矩阵的转置矩阵的三元列表存储的矩阵转置算法

以下列稀疏矩阵为例:                 行下标   列下标  元素值
0 0 8  0 0  0                      0       2      8
0 0 0  0 0  0                      2       0      5
5 0 0  0 16 0                      2       4      16
0 0 18 0 0  0                      3       3      18
0 0 0  9 0  0                      4       3      9
转置后为:
0 0 5  0  0                        0       2      5
0 0 0  0  0                        2       0      8
8 0 0  18 0                        2       3      18
0 0 0  0  9                        3       4      9
0 0 16 0  0                        4       2      16
0 0 0  0  0   

  当稀疏矩阵用三元组顺序表来表示时,是以先行序、后列序的原则存放非零元素的,这样存放有利于稀疏矩阵的运算。然而,若按行列序号直接互换进行转置,则所得的三元组顺序表就不再满足先行序、后列序的原则。

  为了解决此问题,可以这样来进行矩阵转置:扫描转置前的三元组,并按先列序、后行序的原则转置三元组。在原矩阵得到的三元组中,从第0行开始向下搜索列序号为0的元素,找到(2,0,5),则转置为(0,2,5),并存入转置后的三元组顺序表中。接着搜索列序号为1的元素,没找到。再搜索列号为2的元素,找到(0,2,8)并转置为(2,0,8),放入转置后的三元组顺序表中。依次类推,直到扫描完三元组,即可完成矩阵转置,并且转置后的三元组表应满足先行序、后列序的原则。

  (3)求稀疏矩阵的转置矩阵的三元列表存储的矩阵快速转置算法

  矩阵快速转置算法的基本思想是:假设原稀疏矩阵为N,其三元组顺序表为TN,N的转置矩阵为M,其对应的三元组顺序表为TM。先求出N的每一列的第一个非零元素在转置后的TM的行号,然后扫描转置前的TN,把该列上的元素一次存放于TM的相应位置上。由于N中第一列的第一个非零元素一定存储在TM的第一行位置上,若还知道第一列的非零元素个数,则第二列的第一个非零元素在TM中的行号就等于第一列的第一个非零元素在TM中的行号加上第一列的非零元素个数,以此类推。因为原矩阵中三元组存放顺序是先行后列,故对于同一行来说,必定先遇到列号小的元素,这样只需扫描一遍原矩阵N的TN即可。

  num[i]数组表示N中第i列非零元素的个数,依次为:{1,0,2,1,1,0}

  cpot[i]数组表示N中第i列的第一个非零元素在TM中的位置,即cpot[i] = cpot[i-1] +num[i-1],依次为:{0,1,1,3,4,5}

  依次扫描原矩阵N的三元组顺序表TN,当扫描到一个第col列非零元素时,直接将其存放到TM的cpot[col]行号位置上,然后cpot[col]加1,即cpot[col]始终是下一个col列非零元素在TM中的行数。

  也就是说,首先遍历原三元顺序表TN,得到第0个数据元素为(0,2,8),得到它的列数是2,然后根据第2列第一个数组元素在TM中的行数数组可以知道(0,2,8)这个数据元素在TN中肯定是放在第cpot[2]=1行,所以先交换行列然后把(2,0,8)放到TN的第1行,也就是data[1]的位置上,然后将cpot[2]+1=2,这是因为,如果N中同一列有两个数据元素,那么在(0,2,8)下面的那个数据元素肯定是要放在TN中的(2,0,8)的下面,根据矩阵转置的原理很好理解。然后依次类推,就可以得出新的TN顺序表了。

  (4)稀疏矩阵的三元组顺序存储结构的优缺点:可以节省存储空间,并加快运算速度,但在运算过程中,若系数矩阵的非零元素位置发生变化,必将会引起数组中元素的移动,这时,对数组元素进行插入或删除操作就不太方便。针对这个问题,可以采用链式存储结构来表示稀疏矩阵,则进行插入或删除操作会更加方便一些。

  2.稀疏矩阵的十字链表存储。

  (1)当稀疏矩阵中非零元素的位置或个数经常发生变化时,就不宜采用三元组顺序表存储结构,而应该采用链式存储结构表示。

  (2)在十字链表中稀疏矩阵的非零元素用一个结点来表示,每个结点由5个域组成,其中row域存放该非零元素所在行的位置,column域存放该非零元素所在列的位置,value域存放该非零元素的值,right域存放该非零元素同行的下一个非零元素结点指针,down域存放该非零元素同列的下一个非零元素结点指针。同一行的非零元素结点通过right域链接成一个线性链表,同一列的非零元素结点通过down域链接成一个线性链表,每个非零元素结点既是某个行链表的一个结点,又是某个列链表的某个结点,整个稀疏矩阵构成了一个十字交叉的链表,因此称这样的链表为十字链表。

  五、稀疏矩阵的三元组顺序表存储结构的Java语言代码实现:

  • 三元组结点类:
package bigjun.iplab.sparseMatrix;
/*** 稀疏矩阵的三元组结点类*/
public class TripleNode {public int row;     // 行号public int column;  // 列号public int value;   // 数据元素值// 有参数构造方法public TripleNode(int row, int column, int value) {this.row = row;this.column = column;this.value = value;}// 无参数构造方法public TripleNode() {this(0, 0, 0);}}

  • 实现类:
package bigjun.iplab.sparseMatrix;
/*** 稀疏矩阵三元组顺序表类*/
public class SparseMatrix {public TripleNode data[];   // 三元组表public int rows;            // 行数public int columns;            // 列数public int nums;            // 非零元素个数// 稀疏矩阵构造方法1: 为顺序表分配maxSize个存储单元并初始化public SparseMatrix(int maxSize) {data = new TripleNode[maxSize];for (int i = 0; i < data.length; i++) {data[i] = new TripleNode();}rows = 0;columns = 0;nums = 0;}// 稀疏矩阵构造方法2: 根据给定的稀疏矩阵创建你三元组表// 按先行序后列序的原则依次扫描已知稀疏矩阵的所有元素,并把非零元素插入到构造方法1生成的三元组顺序表中public SparseMatrix(int mat[][]) {int i,j, k = 0, count = 0;rows = mat.length;                  // 获取行数columns = mat[0].length;            // 获取列数for (i = 0; i < rows; i++) {        // 统计非零元素的个数for (j = 0; j < columns; j++) {if (mat[i][j] != 0) {count++;}}}nums = count;    // 非零元素的个数data = new TripleNode[nums];   // 调用构造方法1来申请三元组表的结点空间for (i = 0; i < rows; i++) {for (j = 0; j < columns; j++) {if (mat[i][j] != 0) {data[k] = new TripleNode(i, j, mat[i][j]);  // 建立三元组k++;}}}}// 矩阵转置算法public SparseMatrix transpose() {SparseMatrix tMatrix = new SparseMatrix(nums);      // 创建矩阵对象tMatrix.columns = rows;                                // 行数变为列数tMatrix.rows = columns;                                // 列数变为行数tMatrix.nums = nums;                                // 非零元素个数不变int q = 0;for (int i = 0; i < columns; i++) {                    // 从第0行开始搜索for (int j = 0; j < nums; j++) {                // 遍历完所有元素if (data[j].column == i) {                    // 第i行就找列号为i的,先0再1...tMatrix.data[q].row = data[j].column;tMatrix.data[q].column = data[j].row;tMatrix.data[q].value = data[j].value;q++;}}}return tMatrix;}// 矩阵快速转置算法public SparseMatrix fastTranspose() {SparseMatrix tMat = new SparseMatrix(nums);         // 创建矩阵对象tMat.columns = rows;                                // 行数变为列数tMat.rows = columns;                                // 列数变为行数tMat.nums = nums;                                    // 非零元素个数不变int i, j = 0, k = 0;int[] num, cpot;if (nums > 0) {num = new int[columns];   // num[i]表示N中第i列的非零元素个数cpot = new int[columns];   // 每列非零元素个数数组num初始化全部归零for (i = 0; i < columns; i++) { num[i] = 0;}// 计算每列非零元素个数for (i = 0; i < nums; i++) {j = data[i].column;num[j]++;}// 计算每列第1个非零元素在TM中的位置cpot[0] = 0;for (i = 1; i < columns; i++) {cpot[i] = cpot[i-1] +num[i-1];//cpot[i]表示N中第i列的第一个非零元素在TM中的位置
            }// 执行转置操作for (i = 0; i < nums; i++) {           // 扫描整个三元组表j = data[i].column;k = cpot[j];                       // 该元素在TM中的行号tMat.data[k].row = data[i].column;tMat.data[k].column = data[i].row;tMat.data[k].value = data[i].value;cpot[j]++;                            // 该列下一个非零元素的存放位置
            }}return tMat;}// 遍历稀疏矩阵并打印输出public void MatrixTraverse() {System.out.println("稀疏矩阵的三元组存储结构: ");System.out.println("行数: " + rows + ", 列数: " + columns + ", 非零元素个数: " + nums);System.out.println("行下标       列下标           元素值");for (int j = 0; j < nums; j++) {System.out.println(data[j].row + "\t" + data[j].column + "\t" + data[j].value);}}public static void main(String[] args) {int m[][] = {{0, 0, 8,  0,  0,  0},{0, 0, 0,  0,  0,  0},{5, 0, 0,  0,  16, 0},{0, 0, 18, 0,  0,  0},{0, 0, 0,  9,  0,  0}};SparseMatrix sM = new SparseMatrix(m);sM.MatrixTraverse();SparseMatrix tM = sM.transpose();tM.MatrixTraverse();SparseMatrix fM = sM.fastTranspose();fM.MatrixTraverse();}}

  • 输出:
稀疏矩阵的三元组存储结构:
行数: 5, 列数: 6, 非零元素个数: 5
行下标 列下标 元素值
0    2    8
2    0    5
2    4    16
3    2    18
4    3    9
稀疏矩阵的三元组存储结构:
行数: 6, 列数: 5, 非零元素个数: 5
行下标 列下标 元素值
0    2    5
2    0    8
2    3    18
3    4    9
4    2    16
稀疏矩阵的三元组存储结构:
行数: 6, 列数: 5, 非零元素个数: 5
行下标 列下标 元素值
0    2    5
2    0    8
2    3    18
3    4    9
4    2    16

转载于:https://www.cnblogs.com/BigJunOba/p/9205110.html

数据结构(十七)数组和矩阵相关推荐

  1. 数据结构5.1二维数组与矩阵乘法

    二维数组的定义可以采用静态和动态两种,静态数组是在定义的时候就知道了整个二维所需要的空间.在实际应用中大多利用动态数组,灵活度高,不用提前知道矩阵的大小,但在有些情况下,静态数组会更加方便直白.矩阵相 ...

  2. python数组和矩阵用法

    python数组和矩阵 先创建一个一维数组 直接定义一个数组: a = [1,2,3,4,5] b = ['a','c','c','s'] print(a) print(b) 输出结果: 通过键盘输入 ...

  3. asp子窗口读取父窗口数据_算法与数据结构基础 - 数组(Array)

    数组基础 数组是最基础的数据结构,特点是O(1)时间读取任意下标元素,经常应用于排序(Sort).双指针(Two Pointers).二分查找(Binary Search).动态规划(DP)等算法.顺 ...

  4. c语言程序设计5*5矩阵求出,实用C语言程序设计教程5数组和矩阵ppt221.ppt

    实用C语言程序设计教程5数组和矩阵ppt221 C语言程序设计 - 第5章 数组和矩阵 第5章 构造数据-- 数组和矩阵 本章教学目标 1.理解C语言中数组的本质及其在内存的存储结构 2.应用数组表示 ...

  5. matlab怎么输入二维数组,MATLAB二维数组(矩阵)的创建

    MATLAB 二维数组与矩阵之间有很大的相关性,二维数组是由实数或复数排列成矩形构成的,而且从数据结构上看,矩阵和二维数组没有区别. 本节将讲解 MATLAB 二维数组的两种创建方式. 直接输入 矩阵 ...

  6. 数据结构与算法-三对角矩阵的压缩公式推导

    数据结构与算法-三对角矩阵的压缩公式推导 三对角矩阵 压缩公式推导 (1)考虑a[i,j]处在第2到第n-1行之间: 我们可以看到,从第二行开始,元素的个数都为3个.对于a[i,j]将要存储的数组下标 ...

  7. “数组、矩阵与广义表”学习提纲

    文章目录 前言 数组 多维数组的存储方式 矩阵 常见的特殊矩阵 对称矩阵的压缩存储计算 三角矩阵的压缩存储计算 三对角矩阵的压缩存储计算 稀疏矩阵的压缩存储方式 广义表 广义表的属性 广义表的存储方式 ...

  8. 二维数组练习--矩阵的加法和乘法

    数组的练习示例展示: package arrayList; /*** 矩阵的集中运算法则:求和,求积,求逆矩阵,转置矩阵......* @author Drew**/ public class Arr ...

  9. R语言数据结构之数组

    R 语言可以创建一维或多维数组.R 语言数组是一个同一类型的集合,矩阵 matrix 其实就是一个二维数组. Usage array(data = NA, dim = length(data), di ...

  10. python 读取图片成为一维数组_python+opencv 图像的数组和矩阵操作

    在调用opencv的imread函数读取图像时,我们得到的其实是一个类型为numpy.ndarray的n维数组.这个数组的维度是[height,width,3],它是由每个像素的RGB通道的灰度值组成 ...

最新文章

  1. IBM与HP存储数据复制技术PK
  2. 热门的模型跨界,Transformer、GPT做CV任务一文大盘点
  3. Numpy-矩阵的合并
  4. 安卓自定义Listener
  5. 17/100. Maximum Subarray
  6. linux和python的关系_Python、Linux与我的缘分
  7. php中如何配置环境变量,如何配置phpstorm环境变量如何配置phpstorm环境变量
  8. apscheduler 脚本执行失败_在脚本中使用 Bash 信号捕获 | Linux 中国
  9. 关于JFace带复选框的树
  10. 中国元宇宙企业有哪些?
  11. FFmpeg学习(四)-- libavformat 代码组成
  12. 4月30日世界表白日_2020520世界表白日 你该怎么表白
  13. 解决云服务器添加了安全组端口无法访问问题
  14. mysql5.7越用c盘越小_Windows7的C盘可用空间为什么越用越小呢?
  15. “机智歌王”--沙鸥,大陆的的张帝
  16. Pycharm Setting Python Interpreter
  17. 普源精电通过注册:拟募资7.5亿 高瓴与招银是股东
  18. java千克和磅之间的转换,进行打印
  19. 武汉大学计算机学院 优秀夏令营,武汉大学计算机学院2014年优秀大学生暑期夏令营通知...
  20. #3 GPA计算(python)

热门文章

  1. CCNP之IPv6技术-过渡技术(NAT-PT)
  2. 高端存储器研发再获突破 集成电路国产化进程加快
  3. 【linux】16进制格式查看命令hexdump
  4. [转载]Hibernate 一对一 双向关联
  5. Linux怎么取消软链接
  6. 百度开源超级链技术方案!
  7. 300本计算机编程的经典书籍下载
  8. Linux 运维必备的 13 款实用工具,拿好了~
  9. 思科上海被裁员人均赔偿100万?官方回应:大裁员消息不实,中国业务发展不顺为真...
  10. iPhone 12 要来了,手机是时候换到 11 了