工作中,经常需要表示多维数组(如二维矩阵),常见的做法是使用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. HDU——2063 过山车

    过山车 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submis ...

  2. python dos2unix

    有时你在windows上创建的文件拿到Linux/unix上运行会出错, 这是因为windows上有些字符如换行符在linux/unix不识别.这种情况下需要用dos2unix这个工具把文件转换成li ...

  3. jmeter的master-slave模式

    要求: 1.相同的jmeter版本 2.最好相同的java版本 jmeter可以通过master-slave的方式实现更大的并发,但是作为master的机器将会消耗更多的资源,因为所有的slave的压 ...

  4. android的ListView点击item使item展开的做法

    直接上代码把.主要是又一次给item measure高度,直接上代码把 import java.util.ArrayList; import android.app.Activity; import ...

  5. Tomcat启动一半闪退问题解决

    近期刚刚接触Tomcat.对其还不是非常了解. 在这几天,遇到一个Tomcat启动闪退的问题.通过查阅各种资料.算是完美解决.在此分享给朋友们. 首先.确定你的问题在哪里.有两个方法,你能够通过日志去 ...

  6. WebForms UnobtrusiveValidationMode 须要“jquery”ScriptResourceMapping。

    一.问题产生的背景: 在敲牛腩新闻公布系统的后台登录页面的时候,我们用到了RequiredFieldValidator控件(验证非空控件),该控件的作用是禁止输入规定的内容,RequiredField ...

  7. [Canvas画图] 藏图阁(16) 人体穴位

    本节目标: 趁着今天是愚人节.阿伟决定来重温一下学医的那段日子. 有那么一段时间, 阿伟对武侠小说和医学同一时候产生了浓厚的兴趣,当时最想学的就是葵花点穴手, 一阳指之类的点穴功夫.轻轻一点.就能把别 ...

  8. ppt五种经典字体组合

    在做ppt中常常为使用哪种字体而头疼,如今将ppt的经典字体附上.希望对大家有帮助 五种经典的字体组合 标题字体 正文字体 使用场合 方正综艺简体 微软雅黑 课题汇报.咨询报告.学术研讨等正式场合 方 ...

  9. Android架构的简单探讨(一)

    在CSDN上看到这样一篇译文,虽然最终的解决方案要按照自己特定的项目去设计,但该文还是引起了很多自己的共鸣,原文猛戳这里. 这是他提出的基于Messaging的MVC框架: 其中包含的设计思想在于:哪 ...

  10. 混合使用Delphi和C ++(附下载)

    您想将C ++添加到Delphi应用程序中吗?或者将Delphi代码添加到C ++应用程序中?这是如何做. 您可能不知道的一件事是如何在RAD Studio中集成C ++和Delphi语言.您可以将单 ...