数组
数组的定义1:一个 N 维数组是受 N 组线性关系约束的线性表。
二维数组的逻辑结构可形式地描述为:
2_ARRAY(D,R)
其中 D={aij} | i=0,1,…,b1-1; j=0,1,…,b2-1;aij∈D0}
R={Row,Col}
Row={<aij,ai,j+1>|0<=i<=b1-1;0<=j<=b2-2;aij,ai,j+1∈D0}
ai,j+1是aij在行关系中的后继元素。
Col={<aij,ai+1,j>|0<=i<=b1-2;0<=j<=b2-1;aij,ai+1,j∈D0}
ai+1,j是aij在列关系中的后继元素。
①每一个数组元素a[i][j]都受两个关系Row和Col的约束:
ROW(行关系):ai,j+1 是aij在行关系中的直接后继。
COL(列关系):ai+1,j是aij在列关系中的后继元素。
②每个数组元素属于同一数据类型。
③每个数组元素由下标(i,j)唯一确定其位置。
④每个下标i由bi限定其范围,0≤i≤bi-1
n维数组的逻辑结构可描述为:
n_ARRAY(D,R)
D—数组的元素
R—定义为数组元素间的关系
R=(R1,R2,…,Rn)
数组的定义2 :一维数组是定长线性表; 二维数组是一个定长线性表,它的每个元素是一个一维数组;n维数组是线性表,它的每个元素是n-1维数组。
数组是线性结构,基于两点:
1、一个 n维数组被定义为一个线性表,它的元素是一个 n-1维数组。
2、一个 n维数组的数据元素受n个关系的约束,且每个关系都是线性的。
其中: cn =L, ci-1= bi × ci, 1<i ≤ n ; ci 为常数
上式称为n维数组的存储映象函数
数组的基本操作:
1、数组初始化:确定数组维数、长度,分配存储空间。
initarray(&A,n,bound[ ]);
bound[ ]= b1,b2…bn
2、撤消数组
destroyarray (&A);
3、求数组元素值
value(A,&e,index[ ]);
index[ ]= i1,i2,…in
4、为数组元素赋值
assign(&A,e,index[ ]);
数组的顺序表示及实现:
用一遍地址连续的存储单元依次存放数据元素。
1、数据类型描述
#define MAX_ARRAY_DIM 8
** typedef struct {
ElemType *base; //数组元素空间
int dim; //数组维数
int bounds; //数组维长
int constant; //常数因子
}ARRAY;
C语言实现数组基本操作完整代码
#include<stdio.h>
#include<stdlib.h>
#include<stdarg.h>//标准头文件,提供宏va_start、va_arg和va_end用于存取变长参数表
#define MAX_ARRAY_DIM 8//假设数组维数最大值为8
typedef struct {
int* base;//数组元素基址
int dim;//数组维数
int* bound; //数组维界基址,即用于存储每一维的长度
int* constants;//数组映像函数的各个常量系数
}Array;
void InitArray(Array* A, int dim, ...) {
if (dim<1 || dim>MAX_ARRAY_DIM)
return;
A->dim = dim;
A->bound = (int*)malloc(dim * sizeof(int));
int elemtotal = 1;
va_list ap;
va_start(ap, dim);
for (int i = 0; i < dim; i++) {
A->bound[i] = va_arg(ap, int);
elemtotal *= A->bound[i];
}
va_end(ap);
A->base = (int*)malloc(sizeof(int) * elemtotal);
A->constants = (int*)malloc(dim * sizeof(int));
A->constants[dim - 1] = 1;
for (int i = dim - 2; i >= 0; i--) {
A->constants[i] = A->bound[i + 1] * A->constants[i + 1];
}
}
void DestroyArray(Array* A){
if (!A->base)
return;
free(A->base);
A->base = NULL;
if (!A->bound){
return;
}
free(A->bound);
A->bound = NULL;
if (!A->constants){
return;
}
free(A->constants);
A->constants = NULL;
}
bool Locate(Array* A, va_list ap, int* off){
*off = 0;
for (int i = 0; i < A->dim; ++i){
int ind = va_arg(ap, int); //依次取出每一维的下标
if (ind < 0 || ind > A->bound[i])
return false;
(*off) += A->constants[i] * ind;//计算待存取的元素和数组基址的距离
}
return true;
}
void Value(Array* A, int* e, ...){
va_list ap;
va_start(ap, e);
int off;
if (!Locate(A, ap, &off)){
return;
}
*e = *(A->base + off);
}
void Assign(Array* A, int e, ...){
va_list ap;
va_start(ap, e);
int off;
if (!Locate(A, ap, &off)){
return;
}
*(A->base + off) = e;
}
int main(){
Array arr;
InitArray(&arr, 3, 3, 4, 5);
for (int i = 0; i < 3; ++i){
for (int j = 0; j < 4; ++j){
for (int k = 0; k < 5; ++k){
Assign(&arr, i + j + k, i, j, k);
}
}
}
printf("遍历数组arr:\n");
for (int i = 0; i < 3; ++i){
for (int j = 0; j < 4; ++j){
for (int k = 0; k < 5; ++k){
int tmp = 1;
Value(&arr, &tmp, i, j, k);
printf("%5d", tmp);
}
printf("\n");
}
printf("\n");
}
printf("\n");
return 0;
}
矩阵的压缩存储:
1、矩阵压缩存储的概念
特殊矩阵:值相同元素或0元素在矩阵中分布有一定规律。
⒈对称矩阵:矩阵中的元素满足
aij=aji 1≤i,j≤n
⒉三角矩阵:上(下)三角矩阵指矩阵的下(上)三角(不包括对角线)中的元素均为常数c或0的n阶矩阵。
⒊对角矩阵(带状矩阵):矩阵中所有非0元素集中在以主对角线为中心的区域中。
稀疏矩阵:非0元素很少( ≤ 5%)且分布无规律。
2、矩阵的压缩存储
为多个相同值的元分配一个存储单元;对零元不分配空间。
对称矩阵的压缩存储
存储分配策略: 每一对对称元只分配一个存储单元,即只存储下三角(包括对角线)的元, 所需空间数为:
n×(n+1)/2。
存储分配方法: 用一维数组sa[n(n+1)/2]作为存储结构。
sa[k]与aij之间的对应关系为:
稀疏矩阵存储分配策略
只存储稀疏矩阵的非0元素。
矩阵中的一个元素可以用行列下标和其值来唯一表示,因此可以用一个三元组(i,j,aij) 唯一确定一个非0元素。
逻辑上,用三元组表来表示稀疏矩阵的非0元
广义表
广义表的定义
广义表又称为列表(lists),是n≥0个元素a1,a2,…,an的有限序列,记为:
A=( a1,a2,…,an)
其中:
A是广义表的表名,n是广义表的长度
ai 是单个元素或广义表,
若ai是单个元素,则称为广义表的单元素(或原子)。
若是广义表,则称ai是广义表的子表。所以广义表又称为列表。
即 ai ∈D0 或 ai ∈lists
广义表的表头(Head):非空表A 的第一个元素 a1。
广义表的头与a1具有相同的表示形式。
广义表的表尾(Tail):除其头之外的其余元素( a2,…,an)组成的表。
广义表的尾一定是一个广义表。
特点:广义表的定义是一个递归的定义。