1. 数组的基本概念
数组由一组类型相同的数据组成的。可借助线性表的概念递归定义如下:
数组是一个可直接按序号寻找元素的线性表
若 ai(i=1,2,⋯,m−1) a i ( i = 1 , 2 , ⋯ , m − 1 ) 是简单元素,则a是一维数组,当一维数组的每个元素本身又是一个一维数组时,则一维数组扩充成二维数组。以此类推,若 ai a i 是 k−1 k − 1 维数组时,则 a a 为维数组。
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,m−1]
[
0
,
m
−
1
]
中的某个数
map(i1,i2,⋯,in)
m
a
p
(
i
1
,
i
2
,
⋯
,
i
n
)
,使得该下标所对应的元素值存储在一下位置:
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,m−1] [ 0 , m − 1 ] 的方式叫做 行优先映射。下图(b)给出了按列进行连续编号的 列优先映射方式。(行列优先说的是在存储的时候是先存二维数组的列还是行)
对于一个 b1 b 1 行 b2 b 2 列的二维数组的行优先映射对应的映射函数为:
三维的行优先映射函数为:
以此类推, n n 维数组的行优先映射函数为:
其中, cn=1,cj−1=bjcj,1<j≤n c n = 1 , c j − 1 = b j c j , 1 < j ≤ n
在某些语言中,数组各维的下标范围不一定是 [0,bj−1] [ 0 , b j − 1 ] 而是某个闭合区间 [lj,hj] [ l j , h j ] 中的整数,则相应的行优先映射函数也要发生变化。设n维数组的第k维的小标范围为 [lk,hk] [ l k , h k ] ,记:
dk d k 为第k维的长度,则此时有:
列优先的映射函数为:
//.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> ©);//复制构造函数
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> ©)
{
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 (© != 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;
}