数据结构笔记(十六)-- 数组实现

一、数组的结构定义与实现

在这里插入图片描述

typedef int ElemType;//定义数组存储数据类型
typedef struct Array
{
	ElemType *base; // 数组元素基址,由InitArray分配
	int dim; // 数组维数
	int *bounds; // 数组维界基址,由InitArray分配
	int *constants; // 数组映象函数常量基址,由InitArray分配
}Array,pArray;

二、数组概念示意图

以数组a332为例
在这里插入图片描述

三、 数组的操作实现

1、数组操作定义

//1、初始化数组A,可变参数...接收数组每个维度的长度
Status InitArray(Array *A, int dim, ...);
//2、销毁数组A
Status DestroyArray(Array *A);
//3、获取指定数组元素的相对LOC(0,0,...,0)的地址,用off返回
Status Locate(Array A, va_list ap, int *off); 
//4、取出指定位置的数组元素值,指定位置用可变参数 ... 接收,数组指定位置的元素值用e返回
Status Value(ElemType *e, Array A, ...);
//5、修改指定位置的数组元素值,修改为e,位置由可变参数 ... 给出
Status Assign(Array *A, ElemType e, ...);

2、数组的操作实现

2.1、初始化数组A,可变参数…接收数组每个维度的长度

假设初始化数组大小为三维,每一维度长度分别为3、3、2
即a332

![在这里插入图片描述](https://img-blog.csdnimg.cn/20200621165504505.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNjA5NDc1,size_16,color_FFFFFF,t_70

2.1.1、constants的意义和求法,以行序存储为例

首先由笔记十五可以知道以行序存储的数组元素的查找方法,即如下图所示:以数组Am1m2…mN为例求下标为(j1,j2,…,jN)的元素的地址
在这里插入图片描述
改写成下图所示![在这里插入图片描述](https://img-blog.csdnimg.cn/20200621173931894.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQzNjA5NDc1,size_16,color_FFFFFF,t_70以数组Am1m2…mN为例求下标为(j1,j2,…,jN)的元素的地址可写成如下形式
在这里插入图片描述

2.1.2、手算constants值,以行序存储为例

在这里插入图片描述

Status InitArray(Array *A, int dim, ...)
{
	//若维数dim和各维长度合法,则构造相应的数组A,并返回OK
	int elemtotal = 1, i; // elemtotal是元素总值
	va_list ap;
	if (dim<1 || dim>MAX_ARRAY_DIM)//数组维度超出范围
		return ERROR;
	(*A).dim = dim;//维度赋值
	(*A).bounds = (int *)malloc(dim * sizeof(int));//动态分配一个内存空间用于存放每个维度的长度(如a[2][3][4],第一个维度长度为2,第一个维度长度为3,第一个维度长度为4)
	if (!(*A).bounds)//如果内存申请失败 即(*A).bounds=NULL,退出程序
		exit(OVERFLOW);
	va_start(ap, dim);//ap指向函数形参列表中dim后的那个形参,即指向第一个可变参数在堆栈中的地址
	for (i = 0; i < dim; ++i)//循环数组维度
	{
		(*A).bounds[i] = va_arg(ap, int);//取出一个可变形参,接着ap再指向下一个形参,这里形参代表数组的某个维度的长度,即逐一将变长参数赋值给A.bounds[i]
		if ((*A).bounds[i] < 0)//如果某个维度的长度小于0,则不符合要求
			return UNDERFLOW;
		elemtotal *= (*A).bounds[i];//累乘,计算数组中一共有多少个元素 数组元素总数 = 各个维度的长度之积
	}
	va_end(ap);//释放指针,结束可变参数的使用
	(*A).base = (ElemType *)malloc(elemtotal * sizeof(ElemType));//动态分配此数组要占用的总空间
	if (!(*A).base)//如果内存申请失败 即(*A).base=NULL,退出程序
		exit(OVERFLOW);
	(*A).constants = (int *)malloc(dim * sizeof(int));//动态分配数组偏移量基址
	if (!(*A).constants)//如果内存申请失败 即(*A).constants=NULL,退出程序
		exit(OVERFLOW);
	(*A).constants[dim - 1] = 1;
	for (i = dim - 2; i >= 0; --i)
		(*A).constants[i] = (*A).bounds[i + 1] * (*A).constants[i + 1];//计算每一个维度元素间的偏移量(偏移量单位为“个”以ElemType为单位)
	return OK;
}

2.2 、销毁数组A

在这里插入图片描述

Status DestroyArray(Array *A)
{
	//销毁数组A
	if ((*A).base)
	{
		free((*A).base);
		(*A).base = NULL;
	}
	else
		return ERROR;
	if ((*A).bounds)
	{
		free((*A).bounds);
		(*A).bounds = NULL;
	}
	else
		return ERROR;
	if ((*A).constants)
	{
		free((*A).constants);
		(*A).constants = NULL;
	}
	else
		return ERROR;
	return OK;
}

2.3、获取指定数组元素的相对LOC(0,0,…,0)的地址,用off返回

这是一个被调用函数,用于计算指定数组元素的相对位置,注意传递的参数中有va_list ap,因此调用函数参数列表中一定要有可变参数。并且使用了va_start()函数获取了可变参数列表的第一个参数的地址
理解图如下:
在这里插入图片描述
在这里插入图片描述
其中j1,j2,…,jn 对应等于var1,var2,… varN

Status Locate(Array A, va_list ap, int *off) // Value()、Assign()调用此函数 */
{
	//ap指针初始时指向堆栈中可变参数的第一个参数。在这里可变参数的数值代表着每一个维度的第参数个位置,
	//即确定了数组中的一个元素如三维数组a[2][3][4]则可变参数分别为为2、3、4初始时ap指向2的地址
	//若ap指示的各下标值合法,则求出该元素在A中的相对地址off
	int i, ind;
	*off = 0;
	for (i = 0; i < A.dim; i++)
	{
		ind = va_arg(ap, int);
		if (ind < 0 || ind >= A.bounds[i])
			return OVERFLOW;
		*off += A.constants[i] * ind;//相对地址求法
	}
	return OK;
}

2.4、取出指定位置的数组元素值,指定位置用可变参数 … 接收,数组指定位置的元素值用e返回

在这里插入图片描述

Status Value(ElemType *e, Array A, ...) //在VC++中,...之前的形参不能是引用类型
{
	//依次为各维的下标值,若各下标合法,则e被赋值为A的相应的元素值
	va_list ap;
	Status result;
	int off;
	va_start(ap, A);//获取可变参数堆列表的第一个参数的地址
	if ((result = Locate(A, ap, &off)) == OVERFLOW) //调用Locate()获取...位置处的元素相对地址,获取失败返回OVERFLOW
		return result;
	*e = *(A.base + off);
	return OK;
}

2.5、修改指定位置的数组元素值,修改为e

与2、4相似

Status Assign(Array *A, ElemType e, ...)
{
	//依次为各维的下标值,若各下标合法,则将e的值赋给A的指定的元素
	va_list ap;
	Status result;
	int off;
	va_start(ap, e);
	if ((result = Locate(*A, ap, &off)) == OVERFLOW) //调用Locate()获取...位置处的元素相对地址
		return result;
	*((*A).base + off) = e;//修改指定位置的数组元素值,修改为e
	return OK;
}

四、 C语言中可变参数的使用

#include<stdarg.h> // 标准头文件,提供宏va_start,va_arg和va_end, 用于存取变长参数表
参考文章
在这里插入图片描述

五、最后给出完整代码

#include<string.h>
#include<malloc.h> 
#include<stdio.h> 
#include<stdlib.h> 
#include<stdarg.h> // 标准头文件,提供宏va_start,va_arg和va_end, 用于存取变长参数表

#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 int ElemType;//定义数组存储数据类型
typedef struct Array
{
	ElemType *base; // 数组元素基址,由InitArray分配
	int dim; // 数组维数
	int *bounds; // 数组维界基址,由InitArray分配
	int *constants; // 数组映象函数常量基址,由InitArray分配
}Array,pArray;
//1、初始化数组A,可变参数...接收数组每个维度的长度
Status InitArray(Array *A, int dim, ...);
//2、销毁数组A
Status DestroyArray(Array *A);
//3、获取指定数组元素的相对LOC(0,0,...,0)的地址,用off返回
Status Locate(Array A, va_list ap, int *off); 
//4、取出指定位置的数组元素值,指定位置用可变参数 ... 接收,数组指定位置的元素值用e返回
Status Value(ElemType *e, Array A, ...);
//5、修改指定位置的数组元素值,修改为e,位置由可变参数 ... 给出
Status Assign(Array *A, ElemType e, ...);

int main()
{
	Array A;
	int i, j, k, *p, dim = 3, bound1 = 3, bound2 = 4, bound3 = 2; //a[3][4][2]数组
	ElemType e, *p1;
	InitArray(&A, dim, bound1, bound2, bound3); //构造3*4*2的3维数组A
	p = A.bounds;
	printf("A.bounds=");
	for (i = 0; i < dim; i++) //顺序输出A.bounds
		printf("%d ", *(p + i));
	p = A.constants;
	printf("\nA.constants=");
	for (i = 0; i < dim; i++) //顺序输出A.constants
		printf("%d ", *(p + i));
	printf("\n%d页%d行%d列矩阵元素如下:\n", bound1, bound2, bound3);
	for (i = 0; i < bound1; i++)
	{
		for (j = 0; j < bound2; j++)
		{
			for (k = 0; k < bound3; k++)
			{
				Assign(&A, i * 100 + j * 10 + k, i, j, k); // 将i*100+j*10+k赋值给A[i][j][k]
				Value(&e, A, i, j, k); //将A[i][j][k]的值赋给e
				printf("A[%d][%d][%d]=%2d ", i, j, k, e); //输出A[i][j][k]
			}
			printf("\n");
		}
		printf("\n");
	}
	p1 = A.base;
	printf("A.base=\n");
	for (i = 0; i < bound1*bound2*bound3; i++) //顺序输出A.base
	{
		printf("%4d", *(p1 + i));
		if (i % (bound2*bound3) == bound2 * bound3 - 1)
			printf("\n");
	}
	DestroyArray(&A);
	return 0;
}


//1、初始化数组A
Status InitArray(Array *A, int dim, ...)
{
	//若维数dim和各维长度合法,则构造相应的数组A,并返回OK
	int elemtotal = 1, i; // elemtotal是元素总值
	va_list ap;
	if (dim<1 || dim>MAX_ARRAY_DIM)//数组维度超出范围
		return ERROR;
	(*A).dim = dim;//维度赋值
	(*A).bounds = (int *)malloc(dim * sizeof(int));//动态分配一个内存空间用于存放每个维度的长度(如a[2][3][4],第一个维度长度为2,第一个维度长度为3,第一个维度长度为4)
	if (!(*A).bounds)//如果内存申请失败 即(*A).bounds=NULL,退出程序
		exit(OVERFLOW);
	va_start(ap, dim);//ap指向函数形参列表中dim后的那个形参,即指向第一个可变参数在堆栈中的地址
	for (i = 0; i < dim; ++i)//循环数组维度
	{
		(*A).bounds[i] = va_arg(ap, int);//取出一个可变形参,接着ap再指向下一个形参,这里形参代表数组的某个维度的长度,即逐一将变长参数赋值给A.bounds[i]
		if ((*A).bounds[i] < 0)//如果某个维度的长度小于0,则不符合要求
			return UNDERFLOW;
		elemtotal *= (*A).bounds[i];//累乘,计算数组中一共有多少个元素 数组元素总数 = 各个维度的长度之积
	}
	va_end(ap);//释放指针,结束可变参数的使用
	(*A).base = (ElemType *)malloc(elemtotal * sizeof(ElemType));//动态分配此数组要占用的总空间
	if (!(*A).base)//如果内存申请失败 即(*A).base=NULL,退出程序
		exit(OVERFLOW);
	(*A).constants = (int *)malloc(dim * sizeof(int));//动态分配数组偏移量基址
	if (!(*A).constants)//如果内存申请失败 即(*A).constants=NULL,退出程序
		exit(OVERFLOW);
	(*A).constants[dim - 1] = 1;
	for (i = dim - 2; i >= 0; --i)
		(*A).constants[i] = (*A).bounds[i + 1] * (*A).constants[i + 1];//计算每一个维度元素间的偏移量(偏移量单位为“个”以ElemType为单位)
	return OK;
}
//2、销毁数组A
Status DestroyArray(Array *A)
{
	//销毁数组A
	if ((*A).base)
	{
		free((*A).base);
		(*A).base = NULL;
	}
	else
		return ERROR;
	if ((*A).bounds)
	{
		free((*A).bounds);
		(*A).bounds = NULL;
	}
	else
		return ERROR;
	if ((*A).constants)
	{
		free((*A).constants);
		(*A).constants = NULL;
	}
	else
		return ERROR;
	return OK;
}
//3、获取指定数组元素的相对LOC(0,0,...,0)的地址,用off返回
Status Locate(Array A, va_list ap, int *off) // Value()、Assign()调用此函数 */
{
	//ap指针初始时指向堆栈中可变参数的第一个参数。在这里可变参数的数值代表着每一个维度的第参数个位置,
	//即确定了数组中的一个元素如三维数组a[2][3][4]则可变参数分别为为2、3、4初始时ap指向2的地址
	//若ap指示的各下标值合法,则求出该元素在A中的相对地址off
	int i, ind;
	*off = 0;
	for (i = 0; i < A.dim; i++)
	{
		ind = va_arg(ap, int);
		if (ind < 0 || ind >= A.bounds[i])
			return OVERFLOW;
		*off += A.constants[i] * ind;//相对地址求法
	}
	return OK;
}
//4、取出指定位置的数组元素值,指定位置用可变参数 ... 接收,数组指定位置的元素值用e返回
Status Value(ElemType *e, Array A, ...) //在VC++中,...之前的形参不能是引用类型
{
	//依次为各维的下标值,若各下标合法,则e被赋值为A的相应的元素值
	va_list ap;
	Status result;
	int off;
	va_start(ap, A);//获取可变参数堆列表的第一个参数的地址
	if ((result = Locate(A, ap, &off)) == OVERFLOW) //调用Locate()获取...位置处的元素相对地址,获取失败返回OVERFLOW
		return result;
	*e = *(A.base + off);
	return OK;
}
//5、修改指定位置的数组元素值,修改为e
Status Assign(Array *A, ElemType e, ...)
{
	//依次为各维的下标值,若各下标合法,则将e的值赋给A的指定的元素
	va_list ap;
	Status result;
	int off;
	va_start(ap, e);
	if ((result = Locate(*A, ap, &off)) == OVERFLOW) //调用Locate()获取...位置处的元素相对地址
		return result;
	*((*A).base + off) = e;//修改指定位置的数组元素值,修改为e
	return OK;
}
  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值