数据结构六: 数组

1. 数组的基本概念

数组由一组类型相同的数据组成的。可借助线性表的概念递归定义如下:
数组是一个可直接按序号寻找元素的线性表

a=(a0,a1,,am1) a = ( a 0 , a 1 , ⋯ , a m − 1 )

ai(i=1,2,,m1) a i ( i = 1 , 2 , ⋯ , m − 1 ) 是简单元素,则a是一维数组,当一维数组的每个元素本身又是一个一维数组时,则一维数组扩充成二维数组。以此类推,若 ai a i k1 k − 1 维数组时,则 a a k维数组。

2. 数组的顺序存储方式

由于数组很少有删除和插入操作,所以数组通常采用顺序存储方式。设n维数组有 m=ni=1bi m = ∏ i = 1 n b i 个元素,其中 bi b i 表示第i维的长度。假设数组存储的首地址为base,数组中的每个元素需要L个存储单元,则整个数组需要 mL m L 个存储空间。为了存取数组中每个特定下标的元素,必须确定下标为 i1,i2,,in i 1 , i 2 , ⋯ , i n 的元素的存储位置。实际上就是把下标 i1,i2,,in i 1 , i 2 , ⋯ , i n 映射到 [0,m1] [ 0 , m − 1 ] 中的某个数 map(i1,i2,,in) m a p ( i 1 , i 2 , ⋯ , i n ) ,使得该下标所对应的元素值存储在一下位置:

Loc(i1,i2,,in)=base+map(i1,i2,,in)L L o c ( i 1 , i 2 , ⋯ , i n ) = b a s e + m a p ( i 1 , i 2 , ⋯ , i n ) L

Loc(i1,i2,,in) L o c ( i 1 , i 2 , ⋯ , i n ) 表示下标为 i1,i2,,in i 1 , i 2 , ⋯ , i n 的数组元素的的存储地址。可以看到,如果已经知道数组的首地址,要确定其他元素的地址,只需要求出 map(i1,i2,,in) m a p ( i 1 , i 2 , ⋯ , i n ) 。接下来讲讲如何确定 map(i1,i2,,in) m a p ( i 1 , i 2 , ⋯ , i n )
对于一维数组: map(i1)=i1 m a p ( i 1 ) = i 1
对于二维数组:各元素可按下图的形式进行排列。第一维下标相同的元素位于同一行,第二维下标相同的元素位于同一列。
这里写图片描述
对于上图中的元素从左至右连续编号,即可得到下图(a)的结果,这种按照行把二维数组中的元素位置映射为 [0,m1] [ 0 , m − 1 ] 的方式叫做 行优先映射。下图(b)给出了按列进行连续编号的 列优先映射方式。(行列优先说的是在存储的时候是先存二维数组的列还是行)
这里写图片描述
对于一个 b1 b 1 b2 b 2 列的二维数组的行优先映射对应的映射函数为:
map(i1,i2)=i1b2+i2 m a p ( i 1 , i 2 ) = i 1 b 2 + i 2

三维的行优先映射函数为:
map(i1,i2i3)=i1b2b3+i2b3+i3 m a p ( i 1 , i 2 , i 3 ) = i 1 b 2 b 3 + i 2 b 3 + i 3

以此类推, n n 维数组的行优先映射函数为:
(76)map(i1,i2i3,,in)=i1b2b3bn+i2b3bn++in(77)=j=1n1ijj=1nbk+in(78)=j=1ncjij

其中, cn=1,cj1=bjcj,1<jn c n = 1 , c j − 1 = b j c j , 1 < j ≤ n
在某些语言中,数组各维的下标范围不一定是 [0,bj1] [ 0 , b j − 1 ] 而是某个闭合区间 [lj,hj] [ l j , h j ] 中的整数,则相应的行优先映射函数也要发生变化。设n维数组的第k维的小标范围为 [lk,hk] [ l k , h k ] ,记:
dk=hklk+1,k=1,2,3,,n d k = h k − l k + 1 , k = 1 , 2 , 3 , ⋯ , n

dk d k 为第k维的长度,则此时有:
map(i1,i2i3,,in)=(i1l1)d2d3bn+(i2l2)d3dn++(inln)=j=1n1(ijlj)j=1ndk+(inln)(79)(80) (79) m a p ( i 1 , i 2 , i 3 , ⋯ , i n ) = ( i 1 − l 1 ) d 2 d 3 ⋯ b n + ( i 2 − l 2 ) d 3 ⋯ d n + ⋯ + ( i n − l n ) (80) = ∑ j = 1 n − 1 ( i j − l j ) ∏ j = 1 n d k + ( i n − l n )

列优先的映射函数为:
这里写图片描述

//.hpp文件
#pragma once

#include <iostream>
#include <stdarg.h>
//数组类
template<typename elemType>
class Array
{
protected:
    //数组成员数据
    elemType* base;//数组元素的基地址
    int dim;//数组维度
    int *bounds;//数组各维度的长度
    int* constants;//数组映像函数常量

    //辅助函数
    int Locate(int sub0, va_list &va) const;//求元素在顺序存储中的位置

public:
    //抽象数据类型方法声明以及重载函数
    Array(int d, ...);//由维数和其后各维长度构造数组
    ~Array();//析构函数
    elemType &operator()(int sub0, ...);//重载函数运算符
    Array(const Array<elemType> &copy);//复制构造函数
    Array<elemType>& operator = (const Array<elemType>& copy);//赋值运算符重载
};

//数组类的实现
template<typename elemType>
int Array<elemType>::Locate(int sub0, va_list &va) const
{
    if (!(sub0 >=0 && sub0 < bounds[0]))
    {
        std::cout << "下标出界!" << std::endl;
        return -1;
    }
    else
    {
        int off = constants[0] * sub0;//初始化元素在顺序存储中的位置
        for (int i = 1; i < dim; i++)
        {
            int sub = va_arg(va, int);//取出数组元素下标
            if (!(sub >= 0 && sub < bounds[i]))
            {
                std::cout << "下标越界!" << std::endl;
                return -1;
            }
            off = off + constants[i]*sub;//累加乘积求元素在顺序存储中的位置
        }
        return off;
    }
}

template<typename elemType>
Array<elemType>::Array(int d, ...)
{
    if (d<1)
    {
        std::cout << "维度不能小于1!" << std::endl;
        return;
    }
    dim = d;//数组的维数为1
    bounds = new int[dim];
    va_list va;//变长参数变量
    int elemTotal = 1;//元素总数

    //初始化变量va,用于存储变长参数信息,d为省略号左侧最右边的参数标识符
    va_start(va, d);//第二个参数必须和传入的第一个参数名一致
    for (int i = 0; i < dim; i++)
    {
        bounds[i] = va_arg(va, int);
        elemTotal *= bounds[i];//统计数组总元素个数
    }
    va_end(va);
    base = new elemType[elemTotal];
    constants = new int[dim];//分配数组映射函数常量
    constants[dim - 1] = 1;
    for (int i = dim - 2; i >= 0;i--)
    {
        constants[i] = bounds[i + 1] * constants[i + 1];
    }
}

template<typename elemType>
Array<elemType>::~Array()
{
    if (base != NULL)
    {
        delete[] base;
    }
    if (bounds != NULL)
    {
        delete[] bounds;
    }
    if (constants != NULL)
    {
        delete[] constants;
    }
}


template<typename elemType>
elemType & Array<elemType>::operator()(int sub0, ...)
{
    va_list va;
    va_start(va, sub0);
    int position = Locate(sub0, va);
    va_end(va);

    return *(base + position);
}

template<typename elemType>
Array<elemType>::Array(const Array<elemType> &copy)
{
    dim = copy.dim;

    int elemTotal = 1;
    bounds = new int[dim];
    constants = new int[dim];
    for (int i = 0; i < dim;i++)
    {
        bounds[i] = copy.bounds[i];
        constants[i] = copy.bounds[i];
        elemTotal *= copy.bounds[i];
    }

    base = new elemType[elemTotal];
    for (int i = 0; i < elemTotal; i++)
    {
        base[i] = copy.base[i];
    }
}


template<typename elemType>
Array<elemType>& Array<elemType>::operator = (const Array<elemType>& copy)
{
    if (&copy != this)
    {
        if (base != NULL) delete[] base;
        if (bounds != NULL) delete[] bounds;
        if (constants != NULL) delete[] constants;

        dim = copy.dim;

        int elemTotal = 1;
        bounds = new int[dim];
        constants = new int[dim];
        for (int i = 0; i < dim; i++)
        {
            bounds[i] = copy.bounds[i];
            constants[i] = copy.bounds[i];
            elemTotal *= copy.bounds[i];
        }

        base = new elemType[elemTotal];
        for (int i = 0; i < elemTotal; i++)
        {
            base[i] = copy.base[i];
        }
    }
    return *this;
}
//测试文件
#include "Array.hpp"

int main(int argc, char* argv[])
{
    Array<int> myArry(2,3,3);
    int count = 1;
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3;j++)
        {
            myArry(i, j) = count;
            count++;
        }
    }

    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            std::cout << myArry(i, j) << std::endl;
        }
    }

    Array<int> myArry2(myArry);
    Array<int> myArry3(3,2,2,2);

    myArry3 = myArry;
    getchar();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值