【数据结构】数组与广义表
二维数组压缩存储
普通二维数组
二维数组有两种存储方式:
- 以列序为主序的存储方式,就是把每一列拼接起来
- 以行序为主序的存储方式,就是把每一行拼接起来
假设每个数据元素占L个存储单元,则二维数组A任意元素的存储位置:(如果是从1开始,i,j都减一)
\[LOC(i,j)=LOC(0,0)+(n\times i+j)L
\]
普通对称矩阵
对于对称矩阵,我们可以为每一对对称元分配一个存储空间,则可以将\(n^2\)个元压缩存储到\(n(n+1)/2\)个元的空间中。
以\(sa[n(n+1)/2]\)作为n阶对称矩阵A的存储结构,则\(sa[k]\)和矩阵元素\(a_{ij}\)之间存在一一对应的关系:(从下标0开始存储)
\(k=\frac{i(i-1)}{2}+j-1\),当\(i\ge j\)
\(k=\frac{j(j-1)}{2}+i-1\),当\(i<j\)
三对角矩阵
将A[1..n][1..n]压缩至B[0..3n-3]时,aij与bk的对应关系为:k=2i+j-3;
将A[1..n][1..n]压缩至B[1..3n-2]时,aij与bk的对应关系为:k=2i+j-2;
稀疏矩阵
利用三元组(i,j,k)分别对应矩阵非零元的行、列、数据。
稀疏矩阵转置
原理:
(1)将a,b矩阵行列值进行交换;
(2)将每个元组中i,j交换;
(3)重排三元组间顺序;
方法:
(1)按照b.data中三元组的次序依次在a.data找到相应的三元组进行转置。
(2)按照a.data中三元组的次序进行转置,并将转置后的三元组置于b中恰当的位置。
#include<iostream>
#define MAX 100
using namespace std;
typedef struct {
int i, j, e;
}list;
typedef struct {
list data[MAX];
int mu, nu, tu;
}TS;
int main()
{
TS M, T;
int num[MAX], cpot[MAX];
int i, t, p, q, col;
cin >> M.mu >> M.nu >> M.tu;
for (i = 0; i < 100; i++)num[i] = 0;
for (i = 1; i <= M.tu; i++)cin >> M.data[i].i >> M.data[i].j >> M.data[i].e;
for (t = 1; t <= M.tu; ++t)++num[M.data[t].j];
cpot[1] = 1;
for (col = 2; col <= M.nu; col++)cpot[col] = cpot[col - 1] + num[col - 1];
printf("num:");
for (i = 1; i <= M.nu; i++)printf("%d,", num[i]);
printf("\ncpot:");
for (i = 1; i <= M.nu; i++)printf("%d,", cpot[i]);
printf("\n");
for (p = 1; p <= M.tu; ++p) {
col = M.data[p].j;
q = cpot[col];
T.data[q].i = M.data[p].j;
T.data[q].j = M.data[p].i;
T.data[q].e = M.data[p].e;
cpot[col]++;
}
for (i = 1; i <= M.tu; i++)printf("%d,%d,%d\n", T.data[i].i, T.data[i].j, T.data[i].e);
return 0;
}
稀疏矩阵乘积
#include<stdio.h>
typedef struct
{
int i, j;
int e;
} Node;
typedef struct
{
Node nodes[105];
int rpos[105];//各行第一个非零元的位置表
int m, n, t;
} Matrix;
int main()
{
//freopen("/Users/zhj/Downloads/test.txt", "r", stdin);
Matrix A, B;
scanf("%d%d%d", &A.m, &A.n, &A.t);
for (int i = 1; i <= A.t; i++)
{
scanf("%d%d%d", &A.nodes[i].i, &A.nodes[i].j, &A.nodes[i].e);
}
int num[1000];
for (int col = 1; col <= A.m; col++)
{
num[col] = 0;
}
for (int i = 1; i <= A.t; i++)
{
num[A.nodes[i].i]++;
}
A.rpos[1] = 1;
for (int col = 2; col <= A.m; col++)
{
A.rpos[col] = A.rpos[col - 1] + num[col - 1];
}
scanf("%d%d%d", &B.m, &B.n, &B.t);
for (int i = 1; i <= B.t; i++)
{
scanf("%d%d%d", &B.nodes[i].i, &B.nodes[i].j, &B.nodes[i].e);
}
for (int col = 1; col <= B.m; col++)
{
num[col] = 0;
}
for (int i = 1; i <= B.t; i++)
{
num[B.nodes[i].i]++;
}
B.rpos[1] = 1;
for (int col = 2; col <= B.m; col++)
{
B.rpos[col] = B.rpos[col - 1] + num[col - 1];
}
Matrix Q;
Q.m = A.m;
Q.n = B.n;
Q.t = 0;//创建答案矩阵
if (A.t * B.t != 0)
{//Q是非零矩阵
for (int arow = 1; arow <= A.m; arow++)
{//处理A的每一行
int ctemp[105] = {0};
Q.rpos[arow] = Q.t + 1;
int tp;//tp是下一行元素在nodes表中位置
if (arow < A.m)
{
tp = A.rpos[arow + 1];
}
else
{
tp = A.t + 1;
}
for (int p = A.rpos[arow]; p < tp; p++)
{//对当前行中每一个非零元,既从当前在nodes表中位置找到下一行元素在nodes表的位置
int brow = A.nodes[p].j;//此为A表中的纵向位置值,在B表中找相应的行号即可
int t;//t仍然为下一行的位置
if (brow < B.m)
{
t = B.rpos[brow + 1];
}
else
{
t = B.t + 1;
}
for (int q = B.rpos[brow]; q < t; q++)
{
int ccol = B.nodes[q].j;//Q中的纵坐标是以B元素中的j来说话的
ctemp[ccol] += A.nodes[p].e * B.nodes[q].e;
}
}
for (int ccol = 1; ccol <= Q.n; ccol++)
{//压缩存储该行的非零元
if (ctemp[ccol])
{//如果此处有值的话
Q.t++;//Q的非零元素多了一个
Q.nodes[Q.t].i = arow;//行号为此时遍历的A的行号
Q.nodes[Q.t].j = ccol;//列号为此时正在进行压缩所遍历到有值的地方
Q.nodes[Q.t].e = ctemp[ccol];//累计的和拷贝过来
}
}
}
}
printf("%d\n", Q.m);
printf("%d\n", Q.n);
printf("%d\n", Q.t);
for (int i = 1; i <= Q.t; i++)
{
printf("%d,%d,%d\n", Q.nodes[i].i, Q.nodes[i].j, Q.nodes[i].e);
}
return 0;
}
广义表的性质
- 表头:广义表第一个元素(广义表非空)
- 表尾:其余元素组成的表(广义表非空),即除了第一个元素之外元素套括号。因此它必定是子表
- 深度:广义表嵌套的括号层数