数组和广义表
数组
- 数组是一种存储结构,是很多语言内建的数据类型。它的操作只有按下标读写。
- 数组是一种逻辑结构。
- 一维数组属于线性结构,但是不是线性表,因为数组中的元素虽然在存储结构上连续,但是在逻辑结构上不一定连续:即数组可以是稀疏的,也不需要顺序存取。一维数组被称为向量。
- 一维数组的元素属于不可分割的原子元素是时,是线性结构。
- 当它的元素为数组时,即多维数组时,是非线性结构。
一维数组
下标从
多维数组
二维数组
二维数组
- 行优先存储:
- 列优先存储:
多维数组
多维数组
- 行优先存储:
- 列优先存储:
压缩矩阵
对称矩阵行优先压缩存储上三角矩阵
用一维数组存储对称矩阵 a[0][0]
、a[0][1]
、a[0][2]
、a[0][n-1]
、a[1][1]
、a[1][2]
、a[1][n-1]
、a[n-1][n-1]
。
对称矩阵列优先压缩存储下三角矩阵
用一维数组存储对称矩阵 a[0][0]
、a[1][0]
、a[1][1]
、a[2][0]
、a[2][1]
、a[2][2]
、a[n-1][0]
、a[n-1][1]
、a[n-1][n-1]
。
三对角矩阵
用一维数组存储三对角矩阵 a[0][0]
、a[0][1]
、a[1][0]
、a[1][1]
、a[1][2]
、a[2][1]
、a[2][2]
、a[n-2][n-2]
、a[n-2][n-1]
、a[n-1][n-2]
、a[n-1][n-1]
。
主要讨论行优先存储的情况:
从矩阵到一维数组
从一维数组到矩阵
稀疏矩阵
设在一个
通常当这个值小于
三元组表
采用三元组
矩阵转置
void fastTransposeSMatrix(SparseMatrix& a, SparseMatrix& b)
{
if (a.terms <= 0) return;
b.rows = a.cols;
b.cols = a.rows;
b.terms = a.terms;
int rowSize = new int[a.cols]; // 记录转置后每一行的非零元素个数
int rowStart = new int[a.cols]; // 在存储转置的过程中,该行该放在三元组表的哪个位置
for (int i = 0; i < a.term; ++i)
++rowSize[a.data[i].col];
for (int i = 1; i < a.cols; ++i)
rowStart[i] = rowStart[i - 1] + rowSize[i - 1]; // 类似于计数排序
for (int i = 0; i < a.term; ++i)
{
int j = rowStart[a.data[i].col];
b.data[j].row = a.data[i].col;
b.data[j].col = a.data[i].row;
b.data[j].value = a.data[i].value;
++rowStart[a.data[i].col];
}
delete[] rowSize;
delete[] rowStart;
}
链表表示
用链表表示稀疏矩阵,可以在运算的过程中有效地动态调整矩阵的大小。
简单链式存储
链表的每个结点是一个四元组
虽然有利于插入和删除操作,但是失去了矩阵的灵活性。
行链表组
每一行用一个链表表示,链表的每个结点是一个三元组
十字链表
每个非零元素是一个六元组
行和列共享同一个头指针结点,
广义表
广义表的定义是 递归 的。 当每个元素均为原子元素且类型相同时,广义表即为线性表。
- 表头:第一个元素,是一个原子元素或者广义表。
- 表尾:除去表头之外的部分,是一个广义表。
- 表长:广义表中最外层的元素个数。
- 深度:广义表中括号 最深 的层数。原子元素的深度为
, 的深度为 。
广义表的性质
- 有次序性:广义表中元素之间有次序关系。
- 有长度:广义表中元素的个数称为广义表的长度。
- 有深度:广义表中元素的嵌套层数称为广义表的深度。
- 可递归:广义表本身可以是自己的子表。
- 可共享:广义表可以被其他子表共享。
广义表的链接表示
头尾表示
广义表 = 表头 + 表尾
tag
:标志域,表示当前元素是原子元素还是广义表。value
:值域,存储原子元素的值。hlink
,tlink
:指针域,分别指向表头和表尾。
每个指针指向的都是一个广义表的头结点,即先在剩下的元素外面加上一层括号。
扩展的线性链表
和头尾表示类似,只不过原子元素也存储了 tlink
指针。 扩展的线性链表的指针直接指向下一个元素,而不是指向广义表的头结点。
层次链表
结合了上述两种表示方法,拥有头指针以及指向下一个元素的指针。