工作中,经常需要表示多维数组(如二维矩阵),常见的做法是使用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. WCF的Binding模型之四:信道工厂(Channel Factory)

    由于信道管理器在客户端和服务端所起的不同作用,分为信道监听器和信道工厂.和服务端的信道监听其相比,处于客户端的信道工厂显得简单.从名称就可以看得出来,信道工厂的作用就是单纯的创建用于消息发送的信道.我 ...

  2. JAVA 流程控制之选择语句

    在程序设计时,有三种基本技术可以改变程序的流程控制: 调用方法: 选择: 循环. 在这里,我们主要来讲讲选择语句. JAVA中的选择语句与C语言中的基本相同,包括: if 语句: if/else 语句 ...

  3. Cocos2dx 小技巧(九)现成的粒子特效

    和高中的她 差点儿相同有两三年没见面了吧.下午她正好来泉州.我俩出来一起吃了个饭. 怎么说呢,自从高中毕业后我俩的联系就少了非常多.大学期间也就见过两三面吧. 现在毕业也快一年了,她已是人妇,而我自己 ...

  4. java 代理模式具体解释

    java 动态代理(JDK和cglib) 设计模式这东东每次看到就明确可过段时间又不能非常流利的说出来.今天就用具体的比喻和实例来加深自己的理解(小弟水平不高有不正确的地方希望大家能指出来). (1) ...

  5. You don&#39;t have permission to access &#215;&#215;&#215; on this server.

    之前开发项目一直在linux上用的xampp集成环境,前几天突然想移到window上面去. 開始在window上安装了一个集成环境(名字大概是 Uniform Service),把项目文件已过去, o ...

  6. Jenkins performance插件生成性能测试报告【待完成】

    https://segmentfault.com/a/1190000018651092 本地window运行 命令执行:F:\study\apache-jmeter-4.0\apache-jmeter ...

  7. SpringMVC学习指南-Spring框架

    Spring框架主要使用依赖注入.实际上,很多牛叉的框架如Google的Guice都是使用依赖注入. ------------------------------------------------- ...

  8. Python extensions for Windows

    Python extensions for Windows pywin32 214 Python extensions for Windows Maintainer: Mark Hammond Hom ...

  9. grep 并列查询 效率 且 或

    find / | grep -v python | grep -v xl_ | grep -v xiaole |grep redis [root@hadoop3 ~]# find / | grep - ...

  10. Kentico中的skin.css的加载

    kentico7中有如下的css引用 第一行的css是  SELECT * FROM dbo.CMS_CssStylesheet表中的css 后面2个对应到的是Kentico7\App_Themes\ ...