数据结构---06---数组---20205106009---郭睿玥

/*郭睿玥第六次算法实验作业*/

/*实验原理
数组的顺序表示和实现
1.存在的主序问题
   由于我们的内存是一维的线性结构,而数组是个多维的结构,则用一组连续存储单元存放
数组元素时就有个次序约定问题。因为我们是用C语言实现,所以我们默认都是使用行主序
(BASIC、COBOL、 PASCAL和C语言)(FORTRAN 语言使用列主序)。
2.存储位置计算
对于数组,一旦规定了它的维数和各维的长度,便可为它分配存储空间。反之,只要给出一
组下标就可求出相应数组元素的存储位置。下面以行序为主序的存储结构进行说明。
假设每个数据元素占L个存储单元,则二维数组A任一元素a(i, j)的存储位置可由下式确定:
            LOC(i, j) = LOC(0, 0)+(b2*i+j) *L
其中LOC(0, 0)是元素a(0, 0)的存储位置,即二维数组A的起始存储位置,也称为基地址。
现将二维数组推广到一般情况,得到n维数组的数据元素存储位置的计算公式
*/

/*实验环境
CodeBlocks*/


/*实验目的
理解数组的逻辑结构和顺序存储方式
掌握数组的建立和使用的特点
*/



/*实验内容
创建x维数组
为x维数组各个元素赋值
打印x维数组各个元素的值
*/



#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;//elemtotal用于计数
    va_list ap;//用于参数个数不定的变量ap
    va_start(ap, dim);//引用函数,获取可变参数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;  //最后的一维是一维数组,其参数固定为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)//如果base不占空间
        return;//返回
    free(A->base);//清空
    A->base = NULL;//首元素是空
    if (!A->bound)//如果bound不占空间
    {
        return;//返回
    }
    free(A->bound);//清空申请的空间
    A->bound = NULL;//置空

    if (!A->constants)//如果constants不占空间
    {
        return;//返回
    }
    free(A->constants);//清空申请的空间
    A->constants = NULL;//置空
}

//ap参数中存放着要存取的元素的下标,off为数组映像函数的常量参数
int Locate(Array *A, va_list ap, int *off)//布尔型函数,定位坐标为(x,y,z,...)的元素在数组中的下标
{
       *off = 0;
    for (int i = 0; i < A->dim; ++i)//根据维度循环
    {
        int ind = va_arg(ap, int);  //依次取出每一维的下标
        if (ind < 0 || ind > A->bound[i])//如果要定位的元素在某一维的坐标值不在范围
            return 0;//返回错误
        (*off) += A->constants[i] * ind;//计算待存取的元素和数组基址的距离,即数组下标
    }
    return 1;//返回
}

//A是n维数组,e是元素变量,随后是n个下标值
//若下标不越界,则将e赋值为所指定的A的元素
void Value(Array *A, int *e, ...)//取值函数,由于维数不确定故,参数数量不确定
{
    va_list ap;//用于参数个数不定的变量ap
    va_start(ap, e);//引用函数,获取可变参数dim的第一个参数的地址
    int off;
    if (!Locate(A, ap, &off))//如果位置为ap的元素不在指定的三维空间以内则返回
    {
        return;//返回
    }

    *e = *(A->base + off);//获取下标为off的元素的值
}

//A是n维数组,e是元素变量,随后是n个下标值
//若下标不越界,则将e赋给指定的A的元素
void Assign(Array *A, int e, ...)//赋值函数
{
    va_list ap;//用于参数个数不定的变量ap
    va_start(ap, e);//引用函数,获取可变参数dim的第一个参数的地址
    int off;
    if (!Locate(A, ap, &off))//如果位置为ap的元素不在指定的三维空间以内则返回
    {
        return;//返回
    }
    *(A->base + off) = e;//将e赋值为所指定的A的元素
}

int main(void)
{
    Array arr;//建立一个数组
    InitArray(&arr, 3, 3, 6, 8);//初始化数组,这个数组是三维的,每维度的长分别为3,6,8,即这个数组一共有144个元素
    for (int i = 0; i < 3; ++i)//每一层循环
    {
        for (int j = 0; j < 6; ++j)//每一列循环
        {
            for (int k = 0; k < 8; ++k)//每一行循环
            {
                Assign(&arr, i + j + k, i, j, k);//为当前元素赋值这个元素位于数组的第i*48+j*8+k个元素
            }
        }
    }

    for (int i = 0; i < 3; ++i)//每一层循环
    {
        for (int j = 0; j < 6; ++j)//每一列循环
        {
            for (int k = 0; k < 8; ++k)//每一行循环
            {
                int tmp = 1;
                Value(&arr, &tmp, i, j, k);//根据在每维度的位置坐标(k,j,i)获取这个元素的值
                printf("%5d", tmp);//输出这个值

            }
            printf("\n");//换行
        }
        printf("\n");//换行
    }
    printf("\n");//换行

    return 0;//结束
}
/*实验结果如下


    0    1    2    3    4    5    6    7
    1    2    3    4    5    6    7    8
    2    3    4    5    6    7    8    9
    3    4    5    6    7    8    9   10
    4    5    6    7    8    9   10   11
    5    6    7    8    9   10   11   12

    1    2    3    4    5    6    7    8
    2    3    4    5    6    7    8    9
    3    4    5    6    7    8    9   10
    4    5    6    7    8    9   10   11
    5    6    7    8    9   10   11   12
    6    7    8    9   10   11   12   13

    2    3    4    5    6    7    8    9
    3    4    5    6    7    8    9   10
    4    5    6    7    8    9   10   11
    5    6    7    8    9   10   11   12
    6    7    8    9   10   11   12   13
    7    8    9   10   11   12   13   14
*/

 

上一篇:第九届图灵杯-金牌厨师


下一篇:Cow and Fields