1.压缩存储
转载自:https://www.cnblogs.com/lnlin/p/6852236.html
/*
数组的压缩储存:
在一些高阶矩阵中,非零元素非常少,此时如果使用二维数组将造成
储存空间的浪费,这时可只储存部分元素,从而提高储存空间的利用
率,通常的做法是为多个相同值的元素只分配一个储存单元,对值为
零的元素不分配储存单元。我们把非零元素个数远小于二维数组总元
素个数,或元素分布呈一定规律的(对称矩阵,三角矩阵,对角矩阵)
特殊矩阵压缩储存。
对称矩阵:
矩阵元素的值与下标的关系: a(i,j) = a(j,i)
我们只需为每一对称元素分配一个储存单元,这样可以将 n*n 个
元素储存在一个 n(n+1)/2 的储存空间里。
假设用以为数组储存上三角或下三角元素。则一维数组的下标 k
与 n 阶对称阵的元素 a(i,j) 的下标对应关系为:
如果 i >= j 时,以下三角储存, k = i*(i+1)/2 + j
如果 i < j 时,以上三角储存, k = j*(j+1)/2 + i
三角矩阵:
分为上三角矩阵和下三角矩阵,其中在上三角矩阵中,下三角元素
全部为一个常数c,下三角矩阵中,上三角元素全部为一个常数c。
以上三角矩阵为例,上三角矩阵的压缩规则是只储存上三角元素,
不储存下三角元素,或只用一个储存单元储存下三角非零元素
用一维数组储存上三角矩阵,采取使用一个储存单元储存下三角元
素的方法,一维数组的长度为 n*(n+1)/2 + 1 一维数组的下标 k与
n 阶上三角矩阵的元素 a(i,j) 的下标对应关系为:
如果 i <= j, k = i*(2n-i+1)/2 + j -i
如果 i > j , k = n*(n+1)/2
下三角矩阵使用一维数组储存后相应的对应关系为:
如果 i >= j, k = i*(i+1)/2 + j
如果 i < j, k = n*(n+1)/2
其中第 k = n*(n+1)/2 的位置存放的是常数 c
以上三角矩阵为例:
# include <stdio.h>
# define N 5
int main(void)
{
int arry[N][N];
int arr[N*(N+1)/2 + 1] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0};
int i, j, k;
for (i = 0; i < N; ++i)
{
for (j = 0; j < N; ++j)
{
if (i <= j)
{
k = i*(2*N-i+1)/2 + j -i;
arry[i][j] = arr[k];
}
else
{
k = N*(N+1)/2;
arry[i][j] = arr[k];
}
}
}
for (i = 0; i < N; ++i)
{
for (j = 0; j < N; ++j)
printf("%-5d", arry[i][j]);
printf("\n");
}
return 0;
}
输出结果:
2 3 4 5
6 7 8 9
0 10 11 12
0 0 13 14
0 0 0 15
对角矩阵:(数学上的问题 <-0-0->)
也称为带状矩阵,就是所有的非零元素都集中在以对角线为中心的带状
区域内(对角线的个数位奇数),即除了主对角线和主对角线上下若干
条对角线的元素外,其它元素均为常数 c .
*/
/*
假设已有一个 n*n 的 上三角矩阵 A ,且上三角矩阵 A 的元素已按行为主序连续压缩
存放在数组 B 中,设计一个算法,将 B 中的元素案列为主序连续压缩存放在数组 C中
2 3 4 5
6 7 8 9
A(5*5) = 0 0 10 11 12
0 0 13 14
0 0 0 15
其中 B = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0},
C = { 1, 2, 6, 3, 7, 10, 4, 8, 11, 13, 5, 9, 12, 14, 15, 0}.
思路:将一维数组B还原成二维数组A,再将二维数组储存在C中
*/
# include <stdio.h>
# define N 5
void Trans_To_Original(int arry[N][N], int * arr);
void Trans_To_Compress(int arry[N][N], int * arr);
void Show(int arry[N][N], int * arr1, int * arr2);
int main(void)
{
// 创建一个一维数组储存已知的以行为主序压缩后所得元素
int B[(N+1)*N/2 + 1] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0};
int A[N][N] = {0};
Trans_To_Original(A, B);
// 创建一个一维数组储存以列为主序压缩所得的数据
int C[(N+1)*N/2 + 1];
Trans_To_Compress(A, C);
// 将三个数组打印输出
Show(A, B, C);
return 0;
}
void Trans_To_Original(int arry[N][N], int * arr)
{
int i, j, k;
for (i = 0; i < N; ++i)
{
for (j = 0; j < N; ++j)
{
if (i <= j)
{
k = i*(2*N-i+1)/2 + j -i;
arry[i][j] = arr[k];
}
else
{
k = N*(N+1)/2;
arry[i][j] = arr[k];
}
}
}
return;
}
void Trans_To_Compress(int arry[N][N], int * arr)
{
int i, j, k = 0;
// 按列为主序压缩
for (i = 0; i < N; ++i)
{
for (j = 0; j <= i; ++j)
{
arr[k++] = arry[j][i];
}
}
arr[(N+1)*N/2] = 0;
return;
}
void Show(int arry[N][N], int * arr1, int * arr2)
{
int i, j, k;
printf("原二维数组为:\n");
for (i = 0; i < N; ++i)
{
printf(" ");
for (j = 0; j < N; ++j)
{
printf("%-5d", arry[i][j]);
}
printf("\n");
}
printf("以行为主序压缩所得结果为:\n");
for (k = 0; k < (N+1)*N/2; ++k)
{
printf("%-3d", arr1[k]);
}
printf("\n以列为主序压缩所得结果为:\n");
for (k = 0; k < (N+1)*N/2; ++k)
{
printf("%-3d", arr2[k]);
}
printf("\n");
return;
}
2.广义表
转载自:龙猫小爷
链接:https://www.jianshu.com/p/2469a4d9708e
來源:简书
广义表:是由零个或多个原子或子表组成的优先序列,是线性表的推广。
广义表的存储结构
广义表中的数据元素可以具有不同的结构,因此,难以用顺序存储结构表示,通常采用链式存储结构,每个数据元素可用一个节点表示。由于广义表中有两种数据元素,因此需要有两种结构的节点——一种是表结点,一种是原子结点。
表结点由三个域组成:标志域、指示表头的指针的指针域和指示表尾的指针域;而原子域只需两个域:标志域和值域。
表结点由三个域组成:标志域、指示表头的指针域和指向下一个元素的指针;原子结点的三个域为:标志域、值域和指向下一个元素的指针。
3.记录:
(1)对矩阵压缩存储是为了减少存储空间;
(2)()优先级大于【】大于*:
int(*p)[4]-----定义一个p为指向有4个int元素的数组的指针;
int *p[4]-----定义一个存放四个整型指针的数组p
(3)广义表表头空不代表该表为空:广义表()和(())不同,前者是长度为0的空表,对其不能做求表头和表尾的运算,后者为长度为1的非空表,对其可进行分解,得到的表头和表尾均是空表()。