工作中,经常需要表示多维数组(如二维矩阵),常见的做法是使用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. 洛谷 P1023 税收与补贴问题

    P1023 税收与补贴问题 题目背景 每样商品的价格越低,其销量就会相应增大.现已知某种商品的成本及其在若干价位上的销量(产品不会低于成本销售),并假设相邻价位间销量的变化是线性的且在价格高于给定的最 ...

  2. 实战c++中的vector系列--emplace_back造成的引用失效

    上篇将了对于struct或是class为何emplace_back要优越于push_back,可是另一些细节没有提及.今天就谈一谈emplace_back造成的引用失效. 直接撸代码了: #inclu ...

  3. Hadoop HDFS NFS GateWay部署深入具体解释

    目的:通过挂载的方式,能够相似訪问本地磁盘的方式一样的訪问Hadoop文件.简单.方便.快捷. 0.系统版本号&hadoop版本号 1)系统版本号 [root@WEB-W031 sbin]# ...

  4. Android Toast小解

    简单介绍:Toast英文含义是吐司,在Android中.它就像烘烤机里做好的吐司弹出来,并持续一小段时间后慢慢消失. Toast也是一个容器,能够包括各种View,并承载着它们显示. Android中 ...

  5. Android中通过反射来设置Toast的显示时间

    这个Toast的显示在Android中的用途还是非常大的,同一时候我们也知道toast显示的时间是不可控的.我们仅仅能改动他的显示样式和显示的位置,尽管他提供了一个显示时间的设置方法.可是那是没有效果 ...

  6. 在阿里云域名https配置(nginx为例)

    如题: 在阿里云上注册了域名之后在阿里云域名控制台配置https: 1.在域名控制台选择要配置的域名,并在操作栏点击“解析” 2.在域名解析点击更多下的SSL进入到证书列表页,这里有收费的也有免费的, ...

  7. Redis源代码分析(六)--- ziplist压缩列表

    ziplist和之前我解析过的adlist列表名字看上去的非常像.可是作用却全然不同.之前的adlist主要针对的是普通的数据链表操作. 而今天的ziplist指的是压缩链表.为什么叫压缩链表呢.由于 ...

  8. iOS开发----iOS 8的虚化效果

    在iOS 7中,一个重大的改变就是随处可见的虚化,这在通知中心和控制中心表现得尤为抢眼: 然而,当开发人员们着手去将类似的模糊效果增加自己的App的时候,他们会发现有相当严重的障碍. 那时苹果所界定的 ...

  9. Python爬虫【第3篇】【多线程】

    一.多线程 Python标准库提供2个模块,thread是低级模块,threading是高级模块 1.threading模块创建多线程 方式1:把1个函数传入并创建Thread实例,然后调用start ...

  10. 约瑟夫环问题(Josephus)

    约瑟夫环:用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至最后一个元素并输出该元素的值. 一.循环链表:建立一个有N个元素的循环链表,然后从链表头开始遍历并记数,如果计数值为M,则 ...