由一维数组表示的N维数组实现(C++)
工作中,经常需要表示多维数组(如二维矩阵),常见的做法是使用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++)的更多相关文章
- PHP如何判断一个数组是一维数组或者是二维数组?用什么函数?
如题:如何判断一个数组是一维数组或者是二维数组?用什么函数? 判断数量即可 <?php if (count($array) == count($array, 1)) { echo '是一维数组' ...
- C语言数组:C语言数组定义、二维数组、动态数组、字符串数组
1.C语言数组的概念 在<更加优美的C语言输出>一节中我们举了一个例子,是输出一个 4×4 的整数矩阵,代码如下: #include <stdio.h> #include &l ...
- [zt]C++二维数组讲解、二维数组的声明和初始化
定义: int *pia = new int[10]; // array of 10 uninitialized ints 此 new 表达式分配了一个含有 10 个 int 型元素的数组,并返回指向 ...
- 06-01 Java 二维数组格式、二维数组内存图解、二维数组操作
二维数组格式1 /* 二维数组:就是元素为一维数组的一个数组. 格式1: 数据类型[][] 数组名 = new 数据类型[m][n]; m:表示这个二维数组有多少个一维数组. n:表示每一个一维数组的 ...
- ASP数组全集,多维数组和一维数组[转]
ASP数组是比较好用的装载大量数据的容器.1 定义数组 有两种方式:DIM和REDIM. DIM定义的是固定个数.数据类型的数组:而REDIM则不同,它可以定义不同类型的数据,也可以定义个数并非固定的 ...
- C语言 一维数组叠加为二维数组样例
这里参看memcpy的用法,将一个一维整型数组不停的叠加为二维数组 使用宏定义来控制二维数组的行列 代码如下: #include <stdio.h> #include <stdlib ...
- js将一个具有相同键值对的一维数组转换成二维数组
这两天,一个前端朋友在面试的笔试过程中遇到了一道类似于"用js实现将一个具有相同code值的一维数组转换成相同code值在一起的二维数组"的题目.他面试过后,把这个问题抛给了我,问 ...
- js将一维数组转化为二维数组
遇到的问题: 后端返回的是一组一维数组,但是需要展示的格式是二维数组,常见的场景举例:后台返回10个长度的数组,需要分成3个一组展示在banner上. 例:[1,2,3,4,5,6,7,8,9,10] ...
- PHP二维数组(或任意维数组)转换成一维数组的方法汇总(实用)
目录 1 array_reduce函数法 2 array_walk_recursive函数法 3 array_map函数法 假设有下面一个二维数组: $user = array( '0' => ...
随机推荐
- 修改mysql root用户密码(忘记密码)
vi /etc/my.cnf,在[mysqld]中添加 skip-grant-tables 例如: [mysqld] skip-grant-tables datadir=/var/lib/mysql ...
- NA远程
远程网络按照L1分类: 租用专线(Leased Line):一般采用同步串行链路,使用HDLC/PPP封装: 线路交换(Circuit-Switched):一般采用异步串行链路,使用H ...
- [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 ...
- Apple Swift编程语言新手教程
文件夹 1 简单介绍 2 Swift入门 3 简单值 4 控制流 5 函数与闭包 6 对象与类 7 枚举与结构 1 简单介绍 今天凌晨Apple刚刚公布了Swift编程 ...
- MongoDB Helper的简单封装
db.properties #mongodb数据库配置文件 #数据库server所在的ip地址 ip=127.0.0.1 #mongodb服务port号 port=27017 #要连接的库 dbNa ...
- python 简单连接mysql数据库
1. 安装pymysql 库 pip install pymysql 2.实例本地连接mysql库 #!/usr/bin/python # encoding: utf-8 ""&q ...
- J2SE基础:11.异常处理
1:异常的概念: 异常是程序在执行时发生的事件(异常发生在执行期间). 程序出现错误.打断原本的运行流程. 2:Java中处理异常. 在Java中.异常被封装成一个对象.(属性和方法) 3:异常产生 ...
- HDU 4445 数学-抛物运动
D - Crazy Tank ...
- ffmpeg-linux32-v3.3.1
. imageio-binaries/ffmpeg at master · imageio/imageio-binaries · GitHub https://github.com/imageio/i ...
- mystr = '{}{}{}'.format(mystr, random.randint(0, 9), adurl)
mystr = '{}{}{}'.format(mystr, random.randint(0, 9), adurl)