7. 数组 - 数组存储结构、矩阵压缩存储方式

7. 数组 - 数组存储结构、矩阵压缩存储方式

7.1 数组存储结构基本概念

  • 从本质上讲,数组与顺序表、链表、栈和队列一样,都用来存储具有 "一对一" 逻辑关系数据的线性存储结构
  • 根据数组中存储数据之间逻辑结构的不同,数组可细分为一维数组二维数组、…、n 维数组
  • 数组中数据的存储有两种先后存储方式
    • 以列序为主(先列后行):按照行号从小到大的顺序,依次存储每一列的元素
    • 以行序为主(先行后序):按照列号从小到大的顺序,依次存储每一行的元素。
    • 多维数组查找指定元素时,需知道以下信息:
  • 多维数组的存储方式
    • 多维数组在内存中存放的起始地址
    • 该指定元素在原多维数组的坐标(比如说,二维数组中是通过行标和列标来表明数据元素的具体位置的);
    • 数组中数组的具体类型,即数组中单个数据元素所占内存的大小,通常用字母 L 表示;
  • 例如 :
    二维数组采用以行序为主的方式,则在二维数组 a n m a_{nm} anm中查找 a i j a_{ij} aij存放位置的公式为:
    L O C ( i , j ) = L O C ( 0 , 0 ) + ( i ∗ m + j ) ∗ L LOC(i,j) = LOC(0,0) + (i*m + j) * L LOC(i,j)=LOC(0,0)+(im+j)L
    如果采用以列存储的方式,在 a n m a_{nm} anm中查找 a i j a_{ij} aij的方式为:
    L O C ( i , j ) = L O C ( 0 , 0 ) + ( i ∗ n + j ) ∗ L LOC(i,j) = LOC(0,0) + (i*n + j) * L LOC(i,j)=LOC(0,0)+(in+j)L
  • 数据常用来存储矩阵,对矩阵进行操作

7.2 特殊矩阵概念

7.2.1 对称矩阵

  • 对称矩阵 :数据元素沿主对角线对应相等的矩阵
    在这里插入图片描述
  • 压缩存储思想 :由于矩阵中沿对角线两侧的数据相等,因此数组中只需存储对角线一侧(包含对角线)的数据即可,即可以用一维数组存储对称矩阵
  • 压缩公式 :
    存储下三角的元素,只需将各元素所在的行标 i列标 j 代入如下的公式:
    k = i ∗ ( i − 1 ) 2 + j − 1 k = \frac {i*(i-1)}{2 } + j -1 k=2i(i1)+j1
    存储上三角的元素,只需将各元素所在的行标 i列标 j 代入如下的公式:
    k = j ∗ ( j − 1 ) 2 + i − 1 k = \frac {j*(j-1)}{2 } + i -1 k=2j(j1)+i1
    最终求得的 k 值即为该元素存储到数组中的位置(矩阵中元素的行标和列标都从 1 开始),例如上图所示的对称矩阵压缩后为: skr[6] = { 1, 2, 4, 3, 5, 6}

7.2.2 上(下)三角矩阵

  • 主对角线下的数据元素全部相同的矩阵为上三角矩阵(图 a)),主对角线上元素全部相同的矩阵为下三角矩阵(图 b))。
    在这里插入图片描述
  • 压缩存储的方式是:上(下)三角矩阵采用对称矩阵的方式存储上(下)三角的数据(元素 0 不用存储),上(下)三角矩阵存储元素和提取元素的过程和对称矩阵相同。

7.2.3 稀疏矩阵

  • 稀疏矩阵 :矩阵中分布有大量的元素 0,即非 0 元素非常少
    在这里插入图片描述
  • 稀疏矩阵的压缩存储思想为:存储矩阵中的非 0 元素和该元素所在矩阵中的行标和列标,加上矩阵的行数和列数

7.3 稀疏矩阵压缩算法

7.3.1 三元组顺序表

  • 三元组顺序表压缩存储方法的思想为 :按照压缩思想,用一个三元素结构体存储每个非0元素的(行标、列标、元素值),每个三元组顺序存储到一个数组中(该数组为结构体数组),然后存储矩阵的行数、列数、非0元素总个数
// 三元组存储结构的定义
typedef struct {
    int i;      // i : 数据的行标,从1开始
    int j;      // j : 数据的列标,从1开始
    int data;   // data : 非0元素值
}triple;  
typedef struct {
    triple data[number];  // 数据段存储
    int n;                // 矩阵的行数
    int m;                // 矩阵的列数
    int num;              // 非0元素的总个数
}TSMatrix;
  • 示例代码如下:
#include <stdio.h>
#include <stdlib.h>
#define number 3
// 三元组存储结构的定义
typedef struct {
    int i;      // i : 数据的行标,从1开始
    int j;      // j : 数据的列标,从1开始
    int data;   // data : 非0元素值
}triple;  
typedef struct {
    triple data[number];  // 数据段存储
    int n;                // 矩阵的行数
    int m;                // 矩阵的列数
    int num;              // 非0元素的总个数
}TSMatrix;
// 输出存储的稀疏矩阵
void display(TSMatrix M) {
    for (int i = 1; i <= M.n; i++) {
        for (int j = 1; j <= M.m; j++) {
            int value = 0;
            for (int k = 0; k < M.num; k++) {
                if (i == M.data[k].i && j == M.data[k].j) {
                    printf("%d ", M.data[k].data);
                    value = 1;
                    break;
                }
            }
            if (value == 0)
                printf("0 ");
        }
        printf("\n");
    }
}
int main() {
    TSMatrix M;
    M.m = 3;
    M.n = 3;
    M.num = 3;
    M.data[0].i = 1;
    M.data[0].j = 1;
    M.data[0].data = 1;
    M.data[1].i = 2;
    M.data[1].j = 3;
    M.data[1].data = 5;
    M.data[2].i = 3;
    M.data[2].j = 1;
    M.data[2].data = 3;
    display(M);
    return 0;
}

7.3.2 行逻辑链接的顺序表

  • 行逻辑链接的顺序表可以看作是三元组顺序表的升级版,解决了三元组顺序表每次提取指定元素都需要遍历整个数组,运行效率低的问题。
  • 思想为 :在三元组顺序表的基础上,多使用了一个数组,专门记录矩阵中每行第一个非 0 元素在一维数组(三元组结构体数组)中的位置。
// 行逻辑链接的顺序表结构体定义
typedef struct {
    int i;      // i : 数据的行标,从1开始
    int j;      // j : 数据的列标,从1开始
    int data;   // data : 非0元素值
}triple;  
typedef struct {
    triple data[number];   // 数据段存储
    int rpos[num];         // 存储矩阵每行第一个非零元素在data数组中的位置
    int n;                 // 矩阵的行数
    int m;                 // 矩阵的列数
    int num;               // 非0元素的总个数
}RLSMatrix;
  • 示例代码如下:
#include <stdio.h>
#include <stdlib.h>
#define number 5
// 行逻辑链接的顺序表结构体定义
typedef struct {
    int i;      // i : 数据的行标,从1开始
    int j;      // j : 数据的列标,从1开始
    int data;   // data : 非0元素值
}triple;  
typedef struct {
    triple data[number];   // 数据段存储
    int rpos[number];      // 存储矩阵每行第一个非零元素在data数组中的位置
    int n;                 // 矩阵的行数
    int m;                 // 矩阵的列数
    int num;               // 非0元素的总个数
}RLSMatrix;
// 输出存储的稀疏矩阵
void display(RLSMatrix M) {
    for (int i = 1; i <= M.n; i++) {
        for (int j = 1; j <= M.m; j++) {
            int value = 0;
            if (i + 1 <= M.n) {
                for (int k = M.rpos[i]; k < M.rpos[i + 1]; k++) {
                    if (i == M.data[k].i && j == M.data[k].j) {
                        printf("%d ", M.data[k].data);
                        value = 1;
                        break;
                    }
                }
                if (value == 0) {
                    printf("0 ");
                }
            }
            else {
                for (int k = M.rpos[i]; k <= M.num; k++) {
                    if (i == M.data[k].i && j == M.data[k].j) {
                        printf("%d ", M.data[k].data);
                        value = 1;
                        break;
                    }
                }
                if (value == 0) {
                    printf("0 ");
                }
            }
        }
        printf("\n");
    }
}
int main(int argc, char* argv[])
{
    RLSMatrix M;
    M.num = 4;
    M.n = 3;
    M.m = 4;
    M.rpos[1] = 1;
    M.rpos[2] = 3;
    M.rpos[3] = 4;
    M.data[1].data = 3;
    M.data[1].i = 1;
    M.data[1].j = 2;
    M.data[2].data = 5;
    M.data[2].i = 1;
    M.data[2].j = 4;
    M.data[3].data = 1;
    M.data[3].i = 2;
    M.data[3].j = 3;
    M.data[4].data = 2;
    M.data[4].i = 3;
    M.data[4].j = 1;
    display(M);
    return 0;
}

7.3.3 十字链表

  • 十字链表存储稀疏矩阵思想为 :采用的是 "链表+数组" 结构,链表的每个节点存储(行标,列表,元素值,指向下一个列节点的指针,指向下一个行节点的指针);与此同时,所有行链表的表头存储到一个数组(rhead)中,所有列链表的表头存储到另一个数组(chead)中。
  • 每个节点示意图:
    在这里插入图片描述
  • 十字链表存储示意图:
    在这里插入图片描述
  • 链表定义:
typedef struct OLNode
{
    int i, j, e;             // 矩阵三元组 : i代表行, j代表列, e代表当前位置的数据
    struct OLNode* right;    // 指针域 : 右指针
    struct OLNode* down;    //  指针域 : 下指针
}OLNode, * OLink;
typedef struct
{
    OLink* rhead, * chead;  // 行和列链表头指针
    int    mu, nu, tu;     // 矩阵的行数,列数和非零元的个数
}CrossList;
  • 操作示例代码如下:
#include<stdio.h>
#include<stdlib.h>
typedef struct OLNode
{
    int i, j, e;             // 矩阵三元组 : i代表行, j代表列, e代表当前位置的数据
    struct OLNode* right;    // 指针域 : 右指针
    struct OLNode* down;    //  指针域 : 下指针
}OLNode, * OLink;
typedef struct
{
    OLink* rhead, * chead;  // 行和列链表头指针
    int    mu, nu, tu;     // 矩阵的行数,列数和非零元的个数
}CrossList;
CrossList CreateMatrix_OL(CrossList M)
{
    int m, n, t;
    int i, j, e;
    OLNode* p, * q;
    printf("输入矩阵的行数、列数和非0元素个数:");
    scanf("%d %d %d", &m, &n, &t);
    M.mu = m;
    M.nu = n;
    M.tu = t;
    if (!(M.rhead = (OLink*)malloc((m + 1) * sizeof(OLink))) || !(M.chead = (OLink*)malloc((n + 1) * sizeof(OLink))))
    {
        printf("初始化矩阵失败");
        exit(0);
    }
    for (i = 1; i <= m; i++)
    {
        M.rhead[i] = NULL;
    }
    for (j = 1; j <= n; j++)
    {
        M.chead[j] = NULL;
    }
    for (scanf("%d%d%d", &i, &j, &e); 0 != i; scanf("%d%d%d", &i, &j, &e)) {
        if (!(p = (OLNode*)malloc(sizeof(OLNode))))
        {
            printf("初始化三元组失败");
            exit(0);
        }
        p->i = i;
        p->j = j;
        p->e = e;
        //链接到行的指定位置
        if (NULL == M.rhead[i] || M.rhead[i]->j > j)
        {
            p->right = M.rhead[i];
            M.rhead[i] = p;
        }
        else
        {
            for (q = M.rhead[i]; (q->right) && q->right->j < j; q = q->right);
            p->right = q->right;
            q->right = p;
        }
        //链接到列的指定位置
        if (NULL == M.chead[j] || M.chead[j]->i > i)
        {
            p->down = M.chead[j];
            M.chead[j] = p;
        }
        else
        {
            for (q = M.chead[j]; (q->down) && q->down->i < i; q = q->down);
            p->down = q->down;
            q->down = p;
        }
    }
    return M;
}
void display(CrossList M) {
    for (int i = 1; i <= M.nu; i++)
    {
        if (NULL != M.chead[i])
        {
            OLink p = M.chead[i];
            while (NULL != p)
            {
                printf("%d\t%d\t%d\n", p->i, p->j, p->e);
                p = p->down;
            }
        }
    }
}
int main()
{
    CrossList M;
    M.rhead = NULL;
    M.chead = NULL;
    M = CreateMatrix_OL(M);
    printf("输出矩阵M:\n");
    display(M);
    return 0;
}

在这里插入图片描述


感谢阅读 若有错误 敬请见谅!!!


  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

园长QwQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值