工作中,经常需要表示多维数组(如二维矩阵),常见的做法是使用T **pArr;

T **pArr = new T*[M];//创建二维数组[M][N]
for (int i=;i<M;i++)
{
pArr[i] = new T[N];
}

销毁内存:

for (int i=;i<M;i++)
{
delete[] pArr[i];
}
delete[] pArr;

若是三维数组,需要创建三次,T*** pArr;以此类推,操作繁琐。

为方便动态生成多维数组,本文使用一维数据表示多维数组,并基于C++模板和运算符重载,使用一维数组动态表示多维数组,支持数据切片,简化多维数组的处理和使用。

#ifndef MYNDARRAY_H_20170226
#define MYNDARRAY_H_20170226 #include <assert.h>
#include <iostream>
using namespace std; //on dim array represent n-dim array
typedef unsigned int iNum;//使用unsigned int作为后续整数型数据类型 typedef struct stMyRange{//闭区间[start,end]
iNum Start;//start 和end 从 0开始
iNum End;//
stMyRange(){
Start = End = ;
}
stMyRange(iNum start,iNum end){
assert(start >= && end >= start);
Start = start;
End = end;
}
}stMyRange; typedef struct stMyRank{//rank代表一个数据维度
iNum Rank;//数据维度的长度
iNum Start;//数据维度开始位置,start from 0
iNum End;//数据维度结束位置,start from 0
stMyRank(){
Rank = ;//if dim == 0, this rank is not exist
Start = ;//if start ==0 && end == Rank-1, reprsent the whole rank;
End = ;
}
void SetRank(iNum rank){
assert(rank > );
Rank = rank;
Start = ;
End = Rank - ;
}
void SetRange(stMyRange rang){
assert(rang.Start >= && rang.End >= rang.Start && rang.End < Rank);
Start = rang.Start;
End = rang.End;
}
}stMyRank;

//目前设置最大数据维度为4,后续根据需要可扩展
#define MyMaxRank 4 template<class T>
class MyNDArray{//C++模板使用,可表示多种类型的数据
protected:
T* m_pData;//row based storage,行优先存储
stMyRank m_Rank[MyMaxRank];//记录数据维度
iNum m_iRankCap;//total rank capacity;数据维度个数
bool m_isSlice;//if slice==true, it will reuse the m_pData of its parent;//是否是数据切片
public:
MyNDArray(){
m_pData = NULL;
m_iRankCap = ;
m_isSlice = false;
}
MyNDArray(iNum rank1){
m_Rank[].SetRank(rank1);
m_iRankCap = ;
m_isSlice = false;
Init();
}
MyNDArray(iNum rank1,iNum rank2){
m_Rank[].SetRank(rank1);
m_Rank[].SetRank(rank2);
m_iRankCap = ;
m_isSlice = false;
Init();
}
MyNDArray(iNum rank1,iNum rank2,iNum rank3){
m_Rank[].SetRank(rank1);
m_Rank[].SetRank(rank2);
m_Rank[].SetRank(rank3);
m_iRankCap = ;
m_isSlice = false;
Init();
}
MyNDArray(iNum rank1,iNum rank2,iNum rank3,iNum rank4){
m_Rank[].SetRank(rank1);
m_Rank[].SetRank(rank2);
m_Rank[].SetRank(rank3);
m_Rank[].SetRank(rank4);
m_iRankCap = ;
m_isSlice = false;
Init();
}
//创建数据切片,新的ndarray共享partent的pData数据域
MyNDArray(MyNDArray& parent,stMyRank rank1){
m_Rank[]=rank1;
m_iRankCap = ;
m_isSlice = true;
m_pData = parent.GetData();
}
MyNDArray(MyNDArray& parent,stMyRank rank1,stMyRank rank2){
m_Rank[]=rank1;
m_Rank[]=rank2;
m_iRankCap = ;
m_isSlice = true;
m_pData = parent.GetData();
}
MyNDArray(MyNDArray& parent,stMyRank rank1,stMyRank rank2,stMyRank rank3){
m_Rank[]=rank1;
m_Rank[]=rank2;
m_Rank[]=rank3;
m_iRankCap = ;
m_isSlice = true;
m_pData = parent.GetData();
}
MyNDArray(MyNDArray& parent,stMyRank rank1,stMyRank rank2,stMyRank rank3,stMyRank rank4){
m_Rank[]=rank1;
m_Rank[]=rank2;
m_Rank[]=rank3;
m_Rank[]=rank4;
m_iRankCap = ;
m_isSlice = true;
m_pData = parent.GetData();
}
~MyNDArray(){
Clear();
}
void Clear(){
if(!m_isSlice && m_pData != NULL){
delete[] m_pData;
m_pData = NULL;
}
} T* GetData(){
return m_pData;
}
void SetData(T* pData){
m_pData = pData;
}
iNum RankCap(){
return m_iRankCap;
}
iNum RankSize(iNum rank){//start from 1,获取第i维的维度长度
if(rank < ) return ;
return m_Rank[rank-].End - m_Rank[rank-].Start + ;
} MyNDArray Slice(stMyRange rang1){//range start from 0,数据切片
stMyRank rank1 = m_Rank[];
rank1.SetRange(rang1);
MyNDArray res(*this,rank1);
return res;
}
MyNDArray Slice(stMyRange rang1,stMyRange rang2){
stMyRank rank1 = m_Rank[];
rank1.SetRange(rang1);
stMyRank rank2 = m_Rank[];
rank2.SetRange(rang2);
MyNDArray res(*this,rank1,rank2);
return res;
}
MyNDArray Slice(stMyRange rang1,stMyRange rang2,stMyRange rang3){
stMyRank rank1 = m_Rank[];
rank1.SetRange(rang1);
stMyRank rank2 = m_Rank[];
rank2.SetRange(rang2);
stMyRank rank3 = m_Rank[];
rank3.SetRange(rang3);
MyNDArray res(*this,rank1,rank2,rank3);
return res;
}
MyNDArray Slice(stMyRange rang1,stMyRange rang2,stMyRange rang3,stMyRange rang4){
stMyRank rank1 = m_Rank[];
rank1.SetRange(rang1);
stMyRank rank2 = m_Rank[];
rank2.SetRange(rang2);
stMyRank rank3 = m_Rank[];
rank3.SetRange(rang3);
stMyRank rank4 = m_Rank[];
rank4.SetRange(rang4);
MyNDArray res(*this,rank1,rank2,rank3,rank4);
return res;
} //override operator(), 使用MyNDarray arr; arr(1,2,3,4)
T& operator()(iNum r1=,iNum r2=,iNum r3=,iNum r4=){
assert(m_pData != NULL);
return m_pData[StoreIndex(r1,r2,r3,r4)];
}
const T& operator()(iNum r1=,iNum r2=,iNum r3=,iNum r4=) const{
assert(m_pData != NULL);
return m_pData[StoreIndex(r1,r2,r3,r4)];
}
protected:
iNum StoreIndex(iNum r1,iNum r2,iNum r3,iNum r4){//数据存储引擎,以行优先存储
assert(m_iRankCap > );
if(m_isSlice){
r1 += m_Rank[].Start;
r2 += m_Rank[].Start;
r3 += m_Rank[].Start;
r4 += m_Rank[].Start;
}
    //判断数据是否在合法的范围内
if(m_iRankCap >= ) assert(r1 >= m_Rank[].Start && r1 <= m_Rank[].End);
if(m_iRankCap >= ) assert(r2 >= m_Rank[].Start && r2 <= m_Rank[].End);
if(m_iRankCap >= ) assert(r3 >= m_Rank[].Start && r3 <= m_Rank[].End);
if(m_iRankCap >= ) assert(r4 >= m_Rank[].Start && r4 <= m_Rank[].End);
iNum index = ;
index = r1 + m_Rank[].Rank * (
r2 + m_Rank[].Rank * (
r3 + m_Rank[].Rank * r4
));//row based storage return index;
} void Init(){//初始化内存
iNum size = ;
for (int i=;i<m_iRankCap;i++)
{
size *= m_Rank[i].Rank;
}
if(m_iRankCap > && size > )
{
m_pData = new T[size];
}
else
m_pData = NULL;
}
};

//重载输入>>和输出<<,用于数据读取和写入
//override operator >>
template<class T>
istream& operator >> (istream& myin,MyNDArray<T>& arr){
iNum r1,r2,r3,r4;
r1 = arr.RankSize();
r2 = arr.RankSize();
r3 = arr.RankSize();
r4 = arr.RankSize();
iNum rankCap = arr.RankCap();
if(rankCap < ) r2 = ;
if(rankCap < ) r3 = ;
if(rankCap < ) r4 = ; for (int i4=;i4<r4;i4++)
{
for (int i3=;i3<r3;i3++)
{
for (int i2=;i2<r2;i2++)
{
for (int i1=;i1<r1;i1++)
{
myin >> arr(i1,i2,i3,i4);//调用重载的operator(),读取数据
}
}
}
}
return myin;
} //override operator <<
template<class T>
ostream& operator << (ostream& myout,MyNDArray<T>& arr){
iNum r1,r2,r3,r4;
r1 = arr.RankSize();
r2 = arr.RankSize();
r3 = arr.RankSize();
r4 = arr.RankSize();
iNum rankCap = arr.RankCap();
if(rankCap < ) r2 = ;
if(rankCap < ) r3 = ;
if(rankCap < ) r4 = ; for (int i4=;i4<r4;i4++)
{
myout<<"rank4:"<<i4+<<endl;
for (int i3=;i3<r3;i3++)
{
myout<<"rank3:"<<i3+<<endl;
for (int i2=;i2<r2;i2++)
{
for (int i1=;i1<r1;i1++)
{
myout <<arr(i1,i2,i3,i4)<<"\t";
}
myout<<"\n";
}
}
myout<<"\n";
}
return myout;
}
#endif

使用方法:

int main(int argc, char* argv[])
{
MyNDArray<int> ndarr(,,,);
ifstream fin("ndarr.txt",ios::in);
fin>>ndarr;
cout<<ndarr;
stMyRange range1(,);
stMyRange range2(,);
stMyRange range3(,);
stMyRange range4(,);
MyNDArray<int> slice = ndarr.Slice(range1,range2,range3,range4);
cout<<"slice:"<<endl<<slice<<endl;
cin>>ndarr;
return ;
}

ndarr.txt内如如下:


上述测试程序的输出结果为:

35 36

38 39

满足数据切片要求。

参考资料:

C++运算符重载:http://www.cnblogs.com/lfsblack/archive/2012/10/01/2709476.html

python.ndarray简单使用

C++ prime中的模板章节

由一维数组表示的N维数组实现(C++)的更多相关文章

  1. PHP如何判断一个数组是一维数组或者是二维数组?用什么函数?

    如题:如何判断一个数组是一维数组或者是二维数组?用什么函数? 判断数量即可 <?php if (count($array) == count($array, 1)) { echo '是一维数组' ...

  2. C语言数组:C语言数组定义、二维数组、动态数组、字符串数组

    1.C语言数组的概念 在<更加优美的C语言输出>一节中我们举了一个例子,是输出一个 4×4 的整数矩阵,代码如下: #include <stdio.h> #include &l ...

  3. [zt]C++二维数组讲解、二维数组的声明和初始化

    定义: int *pia = new int[10]; // array of 10 uninitialized ints 此 new 表达式分配了一个含有 10 个 int 型元素的数组,并返回指向 ...

  4. 06-01 Java 二维数组格式、二维数组内存图解、二维数组操作

    二维数组格式1 /* 二维数组:就是元素为一维数组的一个数组. 格式1: 数据类型[][] 数组名 = new 数据类型[m][n]; m:表示这个二维数组有多少个一维数组. n:表示每一个一维数组的 ...

  5. ASP数组全集,多维数组和一维数组[转]

    ASP数组是比较好用的装载大量数据的容器.1 定义数组 有两种方式:DIM和REDIM. DIM定义的是固定个数.数据类型的数组:而REDIM则不同,它可以定义不同类型的数据,也可以定义个数并非固定的 ...

  6. C语言 一维数组叠加为二维数组样例

    这里参看memcpy的用法,将一个一维整型数组不停的叠加为二维数组 使用宏定义来控制二维数组的行列 代码如下: #include <stdio.h> #include <stdlib ...

  7. js将一个具有相同键值对的一维数组转换成二维数组

    这两天,一个前端朋友在面试的笔试过程中遇到了一道类似于"用js实现将一个具有相同code值的一维数组转换成相同code值在一起的二维数组"的题目.他面试过后,把这个问题抛给了我,问 ...

  8. js将一维数组转化为二维数组

    遇到的问题: 后端返回的是一组一维数组,但是需要展示的格式是二维数组,常见的场景举例:后台返回10个长度的数组,需要分成3个一组展示在banner上. 例:[1,2,3,4,5,6,7,8,9,10] ...

  9. PHP二维数组(或任意维数组)转换成一维数组的方法汇总(实用)

    目录 1 array_reduce函数法 2 array_walk_recursive函数法 3 array_map函数法 假设有下面一个二维数组: $user = array( '0' => ...

随机推荐

  1. 修改mysql root用户密码(忘记密码)

    vi /etc/my.cnf,在[mysqld]中添加 skip-grant-tables 例如: [mysqld] skip-grant-tables datadir=/var/lib/mysql ...

  2. NA远程

    远程网络按照L1分类:     租用专线(Leased Line):一般采用同步串行链路,使用HDLC/PPP封装:     线路交换(Circuit-Switched):一般采用异步串行链路,使用H ...

  3. [React] Preview and edit a component live with React Live

    In this lesson we'll use React Live to preview and edit a component directly in the browser. React L ...

  4. Apple Swift编程语言新手教程

    文件夹 1   简单介绍 2   Swift入门 3   简单值 4   控制流 5   函数与闭包 6   对象与类 7   枚举与结构 1   简单介绍 今天凌晨Apple刚刚公布了Swift编程 ...

  5. MongoDB Helper的简单封装

    db.properties #mongodb数据库配置文件 #数据库server所在的ip地址 ip=127.0.0.1  #mongodb服务port号 port=27017 #要连接的库 dbNa ...

  6. python 简单连接mysql数据库

    1. 安装pymysql 库 pip install pymysql 2.实例本地连接mysql库 #!/usr/bin/python # encoding: utf-8 ""&q ...

  7. J2SE基础:11.异常处理

    1:异常的概念: 异常是程序在执行时发生的事件(异常发生在执行期间). 程序出现错误.打断原本的运行流程. 2:Java中处理异常. 在Java中.异常被封装成一个对象.(属性和方法) 3:异常产生 ...

  8. HDU 4445 数学-抛物运动

                                                          D - Crazy Tank                                 ...

  9. ffmpeg-linux32-v3.3.1

    . imageio-binaries/ffmpeg at master · imageio/imageio-binaries · GitHub https://github.com/imageio/i ...

  10. mystr = '{}{}{}'.format(mystr, random.randint(0, 9), adurl)

    mystr = '{}{}{}'.format(mystr, random.randint(0, 9), adurl)