【C语言 数据结构】数组与对称矩阵的压缩存储

数组的定义

提到数组,大家首先会想到的是:很多编程语言中都提供有数组这种数据类型,比如 C/C++、Java、Go、C# 等。但本节我要讲解的不是作为数据类型的数组,而是数据结构中提供的一种叫数组的存储结构。

和线性存储结构相比,数组最大的不同是:它存储的数据可以包含多种“一对一”的逻辑关系。举个简单的例子:

在这里插入图片描述
上图中,{a1, a2, a3, a4}、{b1, b2, b3, b4}、{c1, c2, c3, c4}、{d1, d2, d3, d4} 中各自包含的元素具有“一对一”的逻辑关系,同时 a、b、c、d 这 4 个序列也具有“一对一”的逻辑关系。

这样存储不止一种“一对一”逻辑关系的数据,数据结构就推荐使用数组存储结构。


对于数组存储结构,我们可以这样理解它:数组是对线性表的扩展,是一种“特殊”的线性存储结构,用来存储具有多种“一对一”逻辑关系的数据。

实际场景中,存储具有 N 种“一对一”逻辑关系的数据,通常会建立 N 维数组:

  • 一维数组和其它线性存储结构很类似,用来存储只有一种“一对一”逻辑关系的数据:

在这里插入图片描述

  • 二维数组用来存储包含两种“一对一”逻辑关系的数据。二维数组可以看作是存储一维数组的一维数组
    在这里插入图片描述
  • n 维数组用来存储包含 n 种“一对一”逻辑关系的数据,可以看作是存储 n-1 维数组的一维数组;

数组存储结构还具有一些其它的特性,包括:

  • 无论数组的维度是多少,数组中的数据类型都必须一致;
  • 数组一旦建立,它的维度将不再改变;
  • 数组存储结构不会对内部的元素做插入和删除操作,常见的操作有 4 种,分别是初始化数组、销毁数组、取数组中的元素和修改数组中的元素。

数组的顺序表示和实现

数组可以是多维的,而顺序表只能是一维的线性空间。要想将 N 维的数组存储到顺序表中,可以采用以下两种方案:

  • 以列序为主(先列后行):按照行号从小到大的顺序,依次存储每一列的元素;
  • 以行序为主(先行后序):按照列号从小到大的顺序,依次存储每一行的元素。

多维数组中,最常用的是二维数组,接下里就以二维数组为例,讲解数组的顺序存储结构。
在这里插入图片描述
所示的二维数组按照“列序为主”的方案存储时,数组中的元素在顺序表中的存储状态如下图所示:
在这里插入图片描述
同样的道理,按照“行序为主”的方案存储数组时,各个元素在顺序表中的存储状态如图
在这里插入图片描述


顺序表中查找和修改数组元素

注意,只有在顺序表内查找到数组中的目标元素之后,才能对该元素执行读取和修改操作。

在 N 维数组中查找目标元素,需知道以下信息:

  • 数组的存储方式;
  • 数组在内存中存放的起始地址;
  • 目标元素在数组中的坐标。比如说,二维数组中是通过行标和列标来确定元素位置的;
  • 数组中元素的类型,即数组中单个数据元素所占内存的大小,通常用字母 L 表示;

根据存储方式的不同,查找目标元素的方式也不同。仍以二维数组为例,如果数组采用“行序为主”的存储方式,则在二维数组 anm 中查找 aij 位置的公式为:

LOC(i, j) = LOC(0, 0) + (i * m + j) * L;

其中,LOC(i, j) 为 aij 在内存中的地址,LOC(0, 0) 为二维数组在内存中存放的起始位置(也就是 a00 的位置)。

而如果采用以列存储的方式,在 anm 中查找 aij 的方式为:

LOC(i, j) = LOC(0, 0) + (j * n + i) * L;

根据以上两个公式,就可以在顺序表中找到目标元素,自然也就可以进行读取和修改操作了。


代码实现

#include<stdarg.h>
#include<malloc.h>
#include<stdio.h>
#include<stdlib.h> // atoi()
#include<io.h> // eof()
#include<math.h>

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW 3
#define UNDERFLOW 4
typedef int Status; //Status是函数的类型,其值是函数结果状态代码,如OK等
typedef int Boolean; //Boolean是布尔类型,其值是TRUE或FALSE
typedef int ElemType;

#define MAX_ARRAY_DIM 8 //假设数组维数的最大值为8
typedef struct
{
   
    ElemType* base; //数组元素基址,由InitArray分配
    int dim; //数组维数
    int* bounds; //数组维界基址,由InitArray分配
    int* constants; // 数组映象函数常量基址,由InitArray分配
} Array;

Status InitArray(Array* A, int dim, ...)
{
   
    //若维数dim和各维长度合法,则构造相应的数组A,并返回OK
    int elemtotal = 1, i; // elemtotal是元素总值
    va_list ap;
    if (dim<1 || dim>MAX_ARRAY_DIM)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值