简体   繁体   English

在C ++中使用1-d索引数组访问nd数组元素的更好方法是什么?

[英]A better way to access n-d array element with a 1-d index array in C++?

Recently, I'm doing something about C++ pointers, I got this question when I want to access elements in multi-dimensional array with a 1-dimensional array which contains index. 最近,我正在做一些关于C ++指针的事情,当我想要使用包含索引的一维数组访问多维数组中的元素时,我得到了这个问题。

Say I have a array arr , which is a 4-dimensional array with all elements set to 0 except for arr[1][2][3][4] is 1 , and a array idx which contains index in every dimension for arr , I can access this element by using arr[idx[0]][idx[1]][idx[2]][idx[3]] , or by using *(*(*(*(arr + idx[0]) + idx[1]) + idx[2]) + idx[3]) . 假设我有一个数组arr ,它是一个4维数组,所有元素都设置为0除了arr[1][2][3][4]1 ,还有一个数组idx ,其中包含arr每个维度的索引,我可以使用arr[idx[0]][idx[1]][idx[2]][idx[3]]或使用*(*(*(*(arr + idx[0]) + idx[1]) + idx[2]) + idx[3]) arr[idx[0]][idx[1]][idx[2]][idx[3]]来访问此元素*(*(*(*(arr + idx[0]) + idx[1]) + idx[2]) + idx[3])

The question comes with when n is large, this would be not so good, so I wonder if there is a better way to work with multi-dimensional accessing? 问题是当n很大时,这将不太好,所以我想知道是否有更好的方法来处理多维访问?

#include <bits/stdc++.h>
using namespace std;

#define N 10

int main()
{
    int arr[N][N][N][N] = {0};
    int idx[4] = {1, 2, 3, 4};
    arr[1][2][3][4] = 1;
    cout<<"Expected: "<<arr[1][2][3][4]<<" at "<<&arr[1][2][3][4]<<endl;
    cout<<"Got with ****: ";
    cout<<*(*(*(*(arr + idx[0]) + idx[1]) + idx[2]) + idx[3])<<endl;
    return 0;
}

output 产量

Expected: 1 at 0x7fff54c61f28
Got with ****: 1

I figured out a way to solve this myself. 我想出了一种解决这个问题的方法。

The idea is that use void * pointers, we know that every memory cell holds value or an address of a memory cell, so we can directly compute the offset of the target to the base address. 我们的想法是使用void *指针,我们知道每个存储单元都保存存储单元的值或地址,因此我们可以直接计算目标到基址的偏移量。

In this case, we use void *p = arr to get the base address of the nd array, and then loop over the array idx , to calculate the offset. 在这种情况下,我们使用void *p = arr来获取nd数组的基地址,然后遍历数组idx ,以计算偏移量。

For arr[10][10][10][10] , the offset between arr[0] and arr[1] is 10 * 10 * 10 * sizeof(int) , since arr is 4-d, arr[0] and arr[1] is 3-d, so there is 10 * 10 * 10 = 1000 elements between arr[0] and arr[1] , after that, we should know that the offset between two void * adjacent addresses is 1 byte , so we should multiply sizeof(int) to get the correct offset, according to this, we finally get the exact address of the memory cell we want to access. 对于arr[10][10][10][10]arr[0]arr[1]之间的偏移量是10 * 10 * 10 * sizeof(int) ,因为arr是4-d, arr[0]并且arr[1]是3-d,因此在arr[0]arr[1]之间有10 * 10 * 10 = 1000元素,之后,我们应该知道两个void *相邻地址之间的偏移是1 byte ,所以我们应该乘以sizeof(int)来获得正确的偏移量,根据这个,我们最终得到我们想要访问的存储器单元的确切地址。

Finally, we have to cast void * pointer to int * pointer and access the address to get the correct int value, that's it! 最后,我们必须将void *指针转换为int *指针并访问该地址以获取正确的int值,就是这样!

With void * (not so good) void * (不太好)

#include <bits/stdc++.h>
using namespace std;

#define N 10

int main()
{
    int arr[N][N][N][N] = {0};
    int idx[4] = {1, 2, 3, 4};
    arr[1][2][3][4] = 1;
    cout<<"Expected: "<<arr[1][2][3][4]<<" at "<<&arr[1][2][3][4]<<endl;
    cout<<"Got with ****: ";
    cout<<*(*(*(*(arr + idx[0]) + idx[1]) + idx[2]) + idx[3])<<endl;

    void *p = arr;
    for(int i = 0; i < 4; i++)
        p += idx[i] * int(pow(10, 3-i)) * sizeof(int);
    cout<<"Got with void *:";
    cout<<*((int*)p)<<" at "<<p<<endl;

    return 0;
}

Output 产量

Expected: 1 at 0x7fff5e3a3f18
Got with ****: 1
Got with void *:1 at 0x7fff5e3a3f18

Notice: There is a warning when compiling it, but I choose to ignore it. 注意:编译时会出现警告,但我选择忽略它。

test.cpp: In function 'int main()':
test.cpp:23:53: warning: pointer of type 'void *' used in arithmetic [-Wpointer-arith]
         p += idx[i] * int(pow(10, 3-i)) * sizeof(int);

Use char * instead of void * (better) 使用char *而不是void * (更好)

Since we want to manipulate pointer byte by byte, it would be better to use char * to replace void * . 由于我们希望逐字节操作指针,因此最好使用char *来替换void *

#include <bits/stdc++.h>
using namespace std;

#define N 10

int main()
{
    int arr[N][N][N][N] = {0};
    int idx[4] = {1, 2, 3, 4};
    arr[1][2][3][4] = 1;
    cout<<"Expected: "<<arr[1][2][3][4]<<" at "<<&arr[1][2][3][4]<<endl;

    char *p = (char *)arr;
    for(int i = 0; i < 4; i++)
        p += idx[i] * int(pow(10, 3-i)) * sizeof(int);
    cout<<"Got with char *:";
    cout<<*((int*)p)<<" at "<<(void *)p<<endl;

    return 0;
}

Output 产量

Expected: 1 at 0x7fff4ffd7f18
Got with char *:1 at 0x7fff4ffd7f18

With int * (In this specific case) 使用int * (在此特定情况下)

I have been told it's not a good practice for void * used in arithmetic, it would be better to use int * , so I cast arr into int * pointer and also replace pow . 我被告知在算术中使用void *不是一个好习惯,使用int *会更好,所以我将arr转换为int *指针并替换pow

#include <bits/stdc++.h>
using namespace std;

#define N 10

int main()
{
    int arr[N][N][N][N] = {0};
    int idx[4] = {1, 2, 3, 4};
    arr[1][2][3][4] = 1;
    cout<<"Expected: "<<arr[1][2][3][4]<<" at "<<&arr[1][2][3][4]<<endl;
    cout<<"Got with ****: ";
    cout<<*(*(*(*(arr + idx[0]) + idx[1]) + idx[2]) + idx[3])<<endl;
    int *p = (int *)arr;
    int offset = 1e3;
    for(int i = 0; i < 4; i++)
    {
        p += idx[i] * offset;
        offset /= 10;
    }
    cout<<"Got with int *:";
    cout<<*p<<" at "<<p<<endl;

    return 0;
}

Output 产量

Expected: 1 at 0x7fff5eaf9f08
Got with ****: 1
Got with int *:1 at 0x7fff5eaf9f08

The way you constructor your algorithm for indexing a multi dimensional array will vary depending on the language of choice; 用于索引多维数组的算法构造函数的方式将根据所选语言而有所不同; you have tagged this question with both C and C++. 你用C和C ++标记了这个问题。 I will stick with the latter since my answer would pertain to C++. 我会坚持使用后者,因为我的回答与C ++有关。 For a little while now I've been working on something similar but different so this becomes an interesting question as I was building a multipurpose multidimensional matrix class template. 一段时间以来,我一直在研究类似但不同的东西,所以这成为一个有趣的问题,因为我正在构建一个多用途的多维矩阵类模板。

What I have discovered about higher levels of multi dimensional vectors and matrices is that the order of 3 repetitiously works miracles in understanding the nature of higher dimensions. 关于更高水平的多维向量和矩阵我发现的是,在理解更高维度的本质时,3的顺序重复地创造了奇迹。 Think of this in the geometrical perspective before considering the algorithmic software implementation side of it. 在考虑算法软件实现方面之前,请在几何视角中考虑这一点。

Mathematically speaking Let's consider the lowest dimension of 0 with the first shape that is a 0 Dimensional object. 从数学上讲,让我们考虑0的最低维度,第一个形状是0维对象。 This happens to be any arbitrary point where this point can have an infinite amount of coordinate location properties. 这恰好是该点可以具有无限量的坐标位置属性的任意点。 Points such as p0(0), p1(1), p2(2,2), p3(3,3,3),... pn(n,n,...n) where each of these objects point to a specific locale with the defined number of dimensional attributes. 诸如p0(0),p1(1),p2(2,2),p3(3,3,3),... pn(n,n,... n)之类的点,其中每个对象都指向具有已定义维度属性数的特定区域设置。 This means that there is no linear distance such as length, width, or height and conversely a magnitude in any direction or dimension where this shape or object that has no bounds of magnitude does not define any area, volume or higher dimensions of volume. 这意味着没有诸如长度,宽度或高度之类的线性距离,并且相反地,在任何方向或尺寸上没有任何方向或尺寸的大小,其中该形状或物体没有限定幅度并不限定任何面积,体积或更高的体积尺寸。 Also with these 0 dimensional points there is no awareness of direction which also implies that there is no angle of rotation that defines magnitude. 同样利用这些0维点,不会意识到方向,这也意味着没有定义幅度的旋转角度。 Another thing to consider is that any arbitrary point is also the zero vector. 另一件需要考虑的事情是任何一个点也是零向量。 Another thing to help in understand this is by the use of algebraic polynomials such that f(x) = mx+b which is linear is a One Dimensional equation, shape(in this case a line) or graph, f(x) = x^2 is Two Dimensional, f(x) = x^3 is Three Dimensional, f(x) = x^4 is Four Dimensional and so on up to f(x) = x^n where this would be N Dimensional. 另一个有助于理解这一点的是通过使用代数多项式使得f(x) = mx+b是线性的一维方程,形状(在这种情况下是一条线)或图形, f(x) = x^2是二维的, f(x) = x^3是三维的, f(x) = x^4是四维的,依此类推直到f(x) = x^n ,其中这将是N维。 Length or Magnitude, Direction or Angle of Rotation, Area, Volume, and others can not be defined until you relate two distinct points to give you at least 1 line segment or vector with a specified direction. 在关联两个不同的点以至少为您提供至少1个具有指定方向的线段或矢量之前,不能定义长度或幅度,方向或旋转角度,面积,体积等。 Once you have an implied direction you then have slope. 一旦你有一个隐含的方向,你就有了斜率。

When looking at operations in mathematics the simplest is addition and it is nothing more than a linear translation and once you introduce addition you also introduce all other operations such as subtraction, multiplication, division, powers, and radicals; 当看数学运算时,最简单的是加法,它只不过是一个线性平移,一旦你引入加法,你还会引入所有其他运算,如减法,乘法,除法,幂和根; once you have multiplication and division you define rotation, angles of rotation, area, volume, rates of change, slope (also tangent function), which thus defines geometry and trigonometry which then also leads into integrations and derivatives. 一旦你有乘法和除法,你就可以定义旋转,旋转角度,面积,体积,变化率,斜率(也是正切函数),从而定义几何和三角函数,然后它们也会导致积分和导数。 Yes, we have all had our math lessons but I think that this is important in to understanding how to construct the relationships of one order of magnitude to another, which then will help us to work through higher dimensional orders with ease once you know how to construct it. 是的,我们都有数学课,但我认为这对于理解如何构建一个数量级与另一个数量级的关系很重要,这将有助于我们一旦你知道如何轻松地完成更高维度的订单构建它。 Once you can understand that even your higher orders of operations are nothing more than expansions of addition and subtraction you will begin to learn that their continuous operations are still linear in nature it is just that they expand into multiple dimensions. 一旦你能够理解,即使你的更高级别的操作只不过是加法和减法的扩展,你将开始学习它们的连续操作本质上仍然是线性的,只是它们扩展到多个维度。

Early I stated that the order of 3 repetitiously works miracles so let me explain my meaning. 早期我说过3的顺序重复地创造了奇迹,所以让我解释一下我的意思。 Since we perceive things on a daily basis in the perspective of 3D; 因为我们从3D的角度每天感知事物; we can only visualize 3 distinct vectors that are orthogonal to each other giving you our natural 3 Dimensions of Space such as Left & Right, Forward & Backward giving you the Horizontal axis and planes and Up & Down giving you the Vertical axis and planes. 我们只能看到3个彼此正交的不同矢量,为您提供我们自然的3维空间,如左右,前进和后退,为您提供水平轴和平面,向上和向下为您提供垂直轴和平面。 We can not visualize anything higher so dimensions of the order of x^4, x^5, x^6 etc... we can not visualize but yet they do exist. 我们无法想象任何更高的东西,所以x^4, x^5, x^6 etc...维度x^4, x^5, x^6 etc...我们无法想象,但它们确实存在。 If we begin to look at the graphs of the mathematical polynomials we can begin to see a pattern between odd and even functions where x^4, x^6, x^8 are similar where they are nothing more than expansions of x^2 and functions of x^5, x^7 & x^9 are nothing more than expansions of x^3 . 如果我们开始查看数学多项式的图形,我们就可以开始看到奇数和偶数函数之间的模式,其中x^4, x^6, x^8是相似的,它们只不过是x^2扩展和x^5, x^7 & x^9x^3只不过是x^3扩展。 So I consider the first few dimensions as normal: Zero - Point, 1st - Linear, 2nd - Area, and 3rd - Volume and as for the 4th and higher dimensions I call all of them Volumetric. 所以我认为前几个维度是正常的:零 - 点,第一 - 线性,第二 - 区域和第三 - 体积,对于第四维和更高维,我称它们全部为体积。

So if you see me use Volume then it relates directly to the 3rd Dimension where if I refer to Volumetric it relates to any Dimension higher than the 3rd. 因此,如果您看到我使用Volume,那么它直接与第三维度相关,如果我参考Volumetric,它与任何高于第三维的Dimension相关。 Now lets consider a matrix such that you have seen in regular algebra where the common matrices are defined by MxN . 现在让我们考虑一个矩阵,这样你就可以在常规代数中看到,其中公共矩阵由MxN定义。 Well this is a 2D flat matrix that has M * N elements and this matrix also has an area of M * N as well. 那么这是具有M * N元素的2D平面矩阵,并且该矩阵也具有M * N的面积。 Let's expand to a higher dimensional matrix such as MxNxO this is a 3D Matrix with M * N * O elements and now has M * N * O Volume. 让我们扩展到更高维度矩阵,例如MxNxO这是一个具有M * N * O元素的3D矩阵,现在具有M * N * O体积。 So when you visualize this think of the MxN 2D part as being a page to a book and the O components represents each page of a book or slice of a box. 因此,当您想象这时,将MxN 2D部件视为书的页面, O组件表示书的每个页面或盒子的切片。 The elements of these matrices can be anything from a simple value, to an applied operation, to an equation, system of equations, sets or just an arbitrary object as in a storage container. 这些矩阵的元素可以是任何东西,从简单值到应用操作,到方程式,方程组,集合,或者只是存储容器中的任意对象。 So now when we have a matrix that is of the 4th order such as MxNxOxP this now has a 4th dimensional aspect but the easiest way to visualize this is that This would be a 1 dimensional array or vector to where all of its P elements would be a 3D Matrix of a Volume of MxNxO . 所以现在当我们有一个四阶矩阵,如MxNxOxP现在有了第四维方面,但最简单的可视化方法是,这将是一个1维数组或向量,其中所有的P元素都是MxNxO体积的3D矩阵。 When you have a matrix of MxNxOxPxQ now you have a 2D Area Matrix of PxQ where each of those elements are a MxNxO Volume Matrix. 当你有一个矩阵MxNxOxPxQ现在你有一个二维矩阵区PxQ ,其中每一元素是MxNxO音量矩阵。 Then again if you have a MxNxOxPxQxR you now have a 6th dimensional matrix and this time you have a 3D Volume Matrix where each of the PxQxR elements are in fact 3D Matrices of MxNxO . 然后,如果你有一个MxNxOxPxQxR你现在有了一个6维矩阵,这次你有一个3D体积矩阵,其中每个PxQxR元素实际上是MxNxO 3D矩阵。 And once you go higher and higher this patter repeats and merges again. 一旦你越来越高,这种模式会重复并再次融合。 So the order of how arbitrary matrices behave is that these dimensionalities repeat: 1D are Linear Vectors or Matrices, 2D are Area or Planar Matrices and 3D is Volume Matrices and any thing of a higher repeats this process compressing the previous step of Volumes thus the terminology of Volumetric Matrices. 因此,任意矩阵如何表现的顺序是这些维度重复:1D是线性向量或矩阵,2D是区域或平面矩阵,3D是体积矩阵,任何更高的东西重复这个过程压缩前一步的卷,因此术语体积矩阵。 Take a Look at this table: 看看这张桌子:

// Order of Magnitude And groupings     
-----------------------------------
Linear         Area          Volume
x^1            x^2           x^3
x^4            x^5           x^6
x^7            x^8           x^9
x^10           x^11          x^12
...            ...           ...
----------------------------------

Now it is just a matter of using a little bit of calculus to know which order of magnitude to index into which higher level of dimensionality. 现在只需要使用一点微积分就可以知道哪个数量级可以指向更高维度的维度。 Once you know a specific dimension it is simple to take multiple derivatives to give you a linear expression; 一旦你知道一个特定的维度,就可以很容易地采用多个导数给你一个线性表达式; then traverse the space, then integrate to the same orders of the multiple derivatives to give the results. 然后遍历空间,然后整合到多个衍生物的相同顺序以给出结果。 This should eliminate a good amount of intermediate work by at first ignoring the least significant lower dimensions in a high dimensional order. 这应该通过首先忽略高维度的最不重要的较低维度来消除大量的中间工作。 If you are working in something that has 12 dimensions you can assume that the first 3 dimensions that define the first set of volume is packed tight being an element to another 3D Volumetric Matrix and then once again that 2d order of Volumetric Matrix is itself an element of another 3D Volumetric Matrix. 如果您正在处理具有12个维度的东西,您可以假设定义第一组体积的前3个维度被紧密包装成另一个3D体积矩阵的元素,然后再次认为体积矩阵的2阶本身就是一个元素另一个3D体积矩阵。 Thus we have a repeating pattern and now it's just a matter of apply this to construct an algorithm and once you have an algorithm; 因此,我们有一个重复的模式,现在只需要应用它来构建一个算法,一旦你有一个算法; it should be quite easy to implement the methods in any programmable language. 用任何可编程语言实现这些方法应该很容易。 So you may have to have a 3 case switch to determine which algorithmic approach to use knowing the overall dimensionality of your matrix or nd array where one handles orders of linearity, another to handle area, and the final to handle volumes and if they are 4th+ then the overall process becomes recursive in nature. 因此,您可能必须使用3个案例切换来确定使用哪种算法方法,了解矩阵或nd数组的整体维度,其中一个处理线性顺序,另一个处理区域,最后处理卷,如果它们是第4个+然后整个过程本质上是递归的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM