以下是这种情况:我正在尝试实现一个与N
维数组一起使用的解决方案,类似下面的代码就可以实现(不是真正的编程语言):
int a[10,14,56]
会创建一个三维数组(即:一个Cuboid),或者:
int a[10,20]
显然会创建一个矩阵。
为了能够表示数据,我决定为元素创建一个“平坦”的存储区域。因此,对于3维向量,我分配10 * 14 * 56
整数,对于第二个,我分配10 * 20
整数。
现在,问题出现了:对于在给定索引处检索元素,解决方案是自我解释1维数组,以及二维数组((i, j)
处的值i
计算行数和j
对数组N x M
中的列进行计数,其中N
是行数,M
是列数)我制定了公式:
array[N, M] -> flat_memory [N * M]
flat_index(i,j) = M * i + j
对于我提出的三维数组:
array[N, M, L] -> flat_memory[N * M * L]
flat_index(i, j, k) = L * i + M * j + k
但是这感觉很糟糕......似乎我无法得到推广的步骤:(所以在这里我转向社区:我的逻辑/计算中的缺陷是什么?那里有任何算法吗?那种问题?
答案 0 :(得分:4)
尝试使用所需的索引写下一些值。因此,对于N = 1,M = 2,L = 3,例如:
i j k index
0 0 0 0
0 0 1 1
0 0 2 2
0 1 0 3
0 1 1 4
0 1 2 5
1 0 0 6
...
现在你可以观察到i
的每次增加,指数应该增加6,
这是M*L
。对于j
的每次增加,索引应该增加3,即L
。
(更一般地说,你需要将一些维度的索引乘以所有不太重要的维度'索引)
所以我们有:
array[N, M, L] -> flat_memory[N * M * L]
flat_index(i, j, k) = M * L * i + L * j + k
这绝不是唯一有效的方法。您可以根据需要重新排列顺序,适当地更改被乘数,这些都是平展它的有效方法:
flat_index(i, j, k) = M * L * i + M * k + j
flat_index(i, j, k) = N * L * j + L * i + k
flat_index(i, j, k) = N * L * j + N * k + i
flat_index(i, j, k) = M * N * k + M * i + j
flat_index(i, j, k) = M * N * k + N * j + i
答案 1 :(得分:2)
我认为一种概括方式如下
阵列[N,M,K] - > flat_memory [N * M * K]
flat_index(i,j,k)=(M * N)* i + M * j + k
阵列[N,M,K,L] - > flat_memory [N * M * K * L]
flat_index(i,j,k,l)=(M * N * K)* i +(M * N)* j + M * k + l
答案 2 :(得分:2)
您可能对以下代码感兴趣,这些代码允许您使用任何“动态”维度:
#include <cassert>
#include <cstddef>
#include <vector>
template<typename T>
class MultiArray
{
public:
explicit MultiArray(const std::vector<size_t>& dimensions) :
dimensions(dimensions),
values(computeTotalSize(dimensions))
{
assert(!dimensions.empty());
assert(!values.empty());
}
const T& get(const std::vector<size_t>& indexes) const
{
return values[computeIndex(indexes)];
}
T& get(const std::vector<size_t>& indexes)
{
return values[computeIndex(indexes)];
}
size_t computeIndex(const std::vector<size_t>& indexes) const
{
assert(indexes.size() == dimensions.size());
size_t index = 0;
size_t mul = 1;
for (size_t i = 0; i != dimensions.size(); ++i) {
assert(indexes[i] < dimensions[i]);
index += indexes[i] * mul;
mul *= dimensions[i];
}
assert(index < values.size());
return index;
}
std::vector<size_t> computeIndexes(size_t index) const
{
assert(index < values.size());
std::vector<size_t> res(dimensions.size());
size_t mul = values.size();
for (size_t i = dimensions.size(); i != 0; --i) {
mul /= dimensions[i - 1];
res[i - 1] = index / mul;
assert(res[i - 1] < dimensions[i - 1]);
index -= res[i - 1] * mul;
}
return res;
}
private:
size_t computeTotalSize(const std::vector<size_t>& dimensions) const
{
size_t totalSize = 1;
for (auto i : dimensions) {
totalSize *= i;
}
return totalSize;
}
private:
std::vector<size_t> dimensions;
std::vector<T> values;
};
让我们测试一下:
int main()
{
MultiArray<int> m({3, 2, 4});
m.get({0, 0, 3}) = 42;
m.get({2, 1, 3}) = 42;
for (size_t i = 0; i != 24; ++i) {
assert(m.computeIndex(m.computeIndexes(i)) == i);
}
return 0;
}
答案 3 :(得分:0)
显然,对于一维数组,您只需要一个索引来处理所有元素:
array[N] -> flat_memory[N] <br />
flat_index(i) = i
如果您添加另一个维度(正如您所说):
array[N, M] -> flat_memory[N * M]<br />
flat_index(i, j) = M * i + j
还有第三个:
array[N, M, K] -> flat_memory[N * M * L]<br />
flat_index(i, j, k) = (M * i + j) * N + k
我认为你现在可以更清楚地看到这种模式了。对于每个新维度,乘以最后一个维度的大小并添加新索引。