我一直在想是否有可能让用户根据给定的数字来决定数组应该有多少“维度”。
让n
为维度数,用户将输入其值。
它将创建一个具有n维的数组。
示例:对于n=5
,它将创建一个名为list的数组,如:int list[size1][size2][size3][size4][size5]
。
用户仍然会提到大小变量,但这实际上是第2部分。
我想知道在声明之后是否可以为数组添加更多维度。如果没有,我想找到解决这个问题的方法。
答案 0 :(得分:2)
C ++语言没有提供可变大小或可变维度的数组。
但是,您可以创建一个类来封装这些行为。
重要的特征是尺寸。您可以使用std::vector<int>
跟踪每个维度的元素数量;例如,{3, 4, 5}
表示三维矩阵,其中最内层的维度为3,中间4和外部5。
使用模板化矢量或双端队列为元素分配空间。所需元素的数量是维度等级的乘积。 (您可以将std::accumulate
与乘法运算符一起使用来计算排名向量。)
接下来,您将需要一个方法来获取一些对象(例如,int的向量),该对象将所有索引提供到访问元素所需的MD数组中。您可以使用一些精美的模板元编程提供带有可变数量参数的重载。
所有这些都超出了一些非常专业的用途,例如:你正在编写类似Mathematica的软件,允许用户玩这些东西。
答案 1 :(得分:1)
您可能对我几个月前实现的数组类感兴趣,该数组类旨在为模拟matlab数组的数组提供语法。它利用initilizer_list语法允许使用
创建任意维数组Array<double> array({10, 20, 30});
然后,您可以使用
访问和修改单个元素double d = array[{1, 2, 3}];
array[{1, 2, 3}] = 10;
甚至使用
将矩阵切成碎片array.getSlice({___, 3, 4});
其中&#34; ___&#34;用作通配符。
详情请见:http://www.second-quantization.com/Array.html
实施:https://github.com/dafer45/TBTK/blob/master/Lib/include/Utilities/TBTK/Array.h
答案 2 :(得分:0)
对象的解决方案让用户选择维度数。有点健壮,我的C ++可能不是最好的,但实现起来很有趣。 nvector<T>
表示可调整大小(在每个维度中的元素的维度和数量)T类型的元素数组,尽管只实现了一些调整大小的函数。 narray<T>
是相同的,但维度的数量不可调整。这解决了使用单个连续数组重新计算多维数组的索引位置的想法。
#include <cstdio>
#include <vector>
#include <iostream>
#include <cstddef>
#include <cstdarg>
#include <algorithm>
#include <numeric>
#include <cassert>
#include <memory>
#include <cstring>
using namespace std;
template<typename T>
class narray {
public:
static size_t compute_size(initializer_list<size_t>& dims) {
return accumulate(dims.begin(), dims.end(), 1, multiplies<size_t>());
}
static size_t compute_size(vector<size_t>& dims) {
return accumulate(dims.begin(), dims.end(), 1, multiplies<size_t>());
}
static size_t compute_distance(vector<size_t>& dims) {
return dims.size() > 1 ? dims[1] : 1;
}
static vector<size_t> remove_one_dim(vector<size_t> dims_) {
return vector<size_t>(dims_.begin() + 1, dims_.end());
}
narray(initializer_list<size_t> dims, T* data) :
dims_(dims), data_(data) {}
narray(vector<size_t> dims, T* data) :
dims_(dims), data_(data) {}
T operator*() {
return *data_;
}
T* operator&() {
return data_;
}
void operator=(T v) {
if (dims_.size() != 0)
throw runtime_error(__PRETTY_FUNCTION__);
*data_ = v;
}
void operator=(initializer_list<T> v) {
if (v.size() > size())
throw runtime_error(__PRETTY_FUNCTION__);
copy(v.begin(), v.end(), data_);
}
T* data() {
return data_;
}
T* data_last() {
return &data()[compute_size(dims_)];
}
size_t size() {
return compute_size(dims_);
}
size_t size(size_t idx) {
return dims_[idx];
}
narray<T> operator[](size_t idx) {
if (dims_.size() == 0)
throw runtime_error(__PRETTY_FUNCTION__);
return narray<T>(remove_one_dim(dims_),
&data_[idx * compute_distance(dims_)]);
}
class iterator {
public:
iterator(initializer_list<size_t>& dims, T* data) :
dims_(dims), data_(data) { }
iterator(vector<size_t>& dims, T* data) :
dims_(dims), data_(data) { }
iterator operator++() {
iterator i = *this;
data_ += compute_distance(dims_);
return i;
}
narray<T> operator*() {
return narray<T>(remove_one_dim(dims_), data_);
}
bool operator!=(const iterator& rhs) {
if (dims_ != rhs.dims_)
throw runtime_error(__PRETTY_FUNCTION__);
return data_ != rhs.data_;
}
private:
vector<size_t> dims_;
T* data_;
};
iterator begin() {
return iterator(dims_, data());
}
iterator end() {
return iterator(dims_, data_last());
}
private:
vector<size_t> dims_;
T* data_;
};
template<typename T>
class nvector {
public:
nvector(initializer_list<size_t> dims) :
dims_(dims), data_(narray<T>::compute_size(dims)) {}
nvector(vector<size_t> dims) :
dims_(dims), data_(narray<T>::compute_size(dims)) {}
nvector(initializer_list<size_t> dims, T* data) :
dims_(dims), data_(data) {}
nvector(vector<size_t> dims, T* data) :
dims_(dims), data_(data) {}
T* data() {
return data_.data();
}
T* data_last() {
return &data()[narray<T>::compute_size(dims_)];
}
size_t size() {
return narray<T>::compute_size(dims_);
}
narray<T> operator&() {
return narray<T>(dims_, data());
}
narray<T> operator[](size_t idx) {
if (dims_.size() == 0)
throw runtime_error(__PRETTY_FUNCTION__);
return narray<T>(narray<T>::remove_one_dim(dims_),
&data()[idx * narray<T>::compute_distance(dims_)]);
}
void operator=(initializer_list<T> v) {
if (v.size() > size())
throw runtime_error(__PRETTY_FUNCTION__);
copy(v.begin(), v.end(), data_.begin());
}
auto begin() {
return typename narray<T>::iterator(dims_, data());
}
auto end() {
return typename narray<T>::iterator(dims_, data_last());
}
// add and remove dimensions
void dimension_push_back(size_t dimsize) {
dims_.push_back(dimsize);
data_.resize(size());
}
void dimension_pop_back() {
dims_.pop_back();
data_.resize(size());
}
// TODO: resize dimension of index idx?
private:
vector<size_t> dims_;
vector<T> data_;
};
int main()
{
nvector<int> A({2, 3});
A = { 1,2,3, 4,5,6 };
assert(A.size() == 6);
assert(&A[0] == &A.data()[0]);
assert(&A[0][0] == &A.data()[0]);
assert(&A[1] == &A.data()[3]);
assert(&A[0][1] == &A.data()[1]);
assert(&A[1][1] == &A.data()[4]);
cout << "Currently array has " << A.size() << " elements: " << endl;
for(narray<int> arr1 : A) { // we iterate over arrays/dimensions
for(narray<int> arr2 : arr1) { // the last array has no dimensions
cout << "elem: " << *arr2 << endl;
}
}
cout << endl;
// assigment example
cout << "Now it is 4: " << *A[1][0] << endl;
A[1][0] = 10;
cout << "Now it is 10: " << *A[1][0] << endl;
return 0;
}
此代码还需要更多工作。它仅作为一个简单的例子。也许在叙述中使用shared_ptr?实施更好的例外? 因此,创建一个n = 5维的数组,其大小为size1,size2,size3,size4和size5,如下所示:
narray<int> arr({size1, size2, size3, size4, size5});
arr[0][1][2][3][4] = 5; // yay!