【数据结构】数组与广义表

二维数组压缩存储

普通二维数组

二维数组有两种存储方式:

  • 以列序为主序的存储方式,就是把每一列拼接起来
  • 以行序为主序的存储方式,就是把每一行拼接起来

假设每个数据元素占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;
}

广义表的性质

  • 表头:广义表第一个元素(广义表非空)
  • 表尾:其余元素组成的(广义表非空),即除了第一个元素之外元素套括号。因此它必定是子表
  • 深度:广义表嵌套的括号层数
posted @ 2021-01-23 11:58  盐析Yuki  阅读(53)  评论(0编辑  收藏  举报
// 侧边栏目录 // https://blog-static.cnblogs.com/files/douzujun/marvin.nav.my1502.css