我最近阅读的一本教科书讨论了行专业和列主要数组。这本书主要关注1维和2维数组,但没有真正讨论3维数组。我正在寻找一些很好的例子,以帮助巩固我对使用row major& amp ;;来解决多维数组中的元素的理解。列主要数组。
+--+--+--+ | / / / /| | +--+--+--+ + | +---+---+---+---+ / / / /|/| | / / / / /| +--+--+--+ + + | +---+---+---+---+ + / / / /|/|/| | / / / / /|/| +--+--+--+ + + + | +---+---+---+---+ + + / / / /|/|/|/| | / / / / /|/|/| +--+--+--+ + + + + | +---+---+---+---+ + + + / / / /|/|/|/|/ | |000|001|002|003|/|/|/| +--+--+--+ + + + + | +---+---+---+---+ + + + |00|01|02|/|/|/|/ | |004|005|006|007|/|/|/| +--+--+--+ + + + | +---+---+---+---+ + + + |03|04|05|/|/|/ | |008|009|00A|00B|/|/|/ +--+--+--+ + + | +---+---+---+---+ + + |06|07|08|/|/ | |00C|00D|00E|00F|/|/ +--+--+--+ + | +---+---+---+---+ + |09|0A|0B|/ | |010|011|012|013|/ +--+--+--+ | +---+---+---+---+ arr[5][3][4] | arr[3][4][5]
注意:原始问题错误地表示为arr [3] [4] [5]。我了解到原始下标代表深度。数据已经过修正,以反映预期的数组表示。
Example hex data +---+---+---+---+ +---+---+---+---+ +---+---+---+---+ |000|001|002|003| |100|101|102|103| |200|201|202|203| +---+---+---+---+ +---+---+---+---+ +---+---+---+---+ |004|005|006|007| |104|105|106|107| |204|205|206|207| +---+---+---+---+ +---+---+---+---+ +---+---+---+---+ |008|009|00A|00B| |108|109|10A|10B| |208|209|20A|20B| +---+---+---+---+ +---+---+---+---+ +---+---+---+---+ |00C|00D|00E|00F| |10C|10D|10E|10F| |20C|20D|20E|20F| +---+---+---+---+ +---+---+---+---+ +---+---+---+---+ |010|011|012|013| |110|111|112|113| |210|211|212|213| +---+---+---+---+ +---+---+---+---+ +---+---+---+---+ slice 0 slice 1 slice 2 short Arr[3][4][5]; // assume array is filled with hex test data arr[1][2][3] = 0x10B use slice 1, row 2, col 3 arr[2][3][4] = 0x210 use slice 2, row 3, col 4 resolves to row 4, col 0
行专业 {000,001,002,003,004,005,006,007,008,009,00A,00B,00C,00D,00E,00F,010011012013, 100,101,102,103,104,105,106,107,108,109,10A,10B,10C,10D,10E,10F,110111112113, 200,201,202,203,204,205,206,207,208,209,20A,20B,20C,20D,20E,20F,210211212213}
专栏专业 {000,004,008,00C,010,001,005,009,00D,011,002,006,00A,00E,012,003,007,00B,00F,013, 100,104,108,10C,110,101,105,109,10D,111,102,106,10A,10E,112,103,107,10B,10F,113, 200,204,208,20C,210,201,205,209,20D,211,202,206,20A,20E,212,203,207,20B,20F,213}Calculation offset for arr[1][2][3] using row major offset? Calculation offset for arr[1][2][3] using column major offset?
答案 0 :(得分:10)
我会看到Row-major order维基百科的文章。有一节描述的尺寸高于2.还有一篇好文章here。该文给出了使用行主要布局的三维数组的以下公式:
Address = Base + ((depthindex*col_size+colindex) * row_size + rowindex) * Element_Size
对于3D阵列:键入A [深度] [col] [行]。基数是数组的起始偏移量。此外,大小变量是每个维度的不同大小。 Element_Size变量表示数组组成的任何类型的大小。
假设你有一个由标准C ++整数组成的行主数组a [4] [6] [5]。要计算1 [3] 2的偏移量,您可以将以下数字插入公式中:
Address = Base + ((1 * 6 + 3) * 5 + 2) * 4
对于具有列主要布局的三维数组,该等式更倾向于:
Address = Base + ((rowindex*col_size+colindex) * depth_size + depthindex) * Element_Size
您使用列主要布局插入上述示例的数字现在是:
Address = Base + ((2 * 6 + 3) * 4 + 1) * 4
答案 1 :(得分:10)
不要通过专注于三维和二维来人为地限制自己。相反,专注于学习解决n维数组的表达式。
表达n维寻址将巩固你对这个主题的掌握,并且更容易记住一个公式而不是单独的公式进行二维和三维寻址。
这是我对n维寻址的尝试:
#define LEN 10
int getValue_nDimensions( int * baseAddress, int * indexes, int nDimensions ) {
int i;
int offset = 0;
for( i = 0; i < nDimensions; i++ ) {
offset += pow(LEN,i) * indexes[nDimensions - (i + 1)];
}
return *(baseAddress + offset);
}
int main() {
int i;
int * baseAddress;
int val1;
int val2;
// 1 dimensions
int array1d[LEN];
int array1d_indexes[] = {2};
int array1d_nDimensions = 1;
baseAddress = &array1d[0];
for(i = 0; i < LEN; i++) { baseAddress[i] = i; }
val1 = array1d[2];
val2 = getValue_nDimensions( // Equivalent to: val1 = array1d[2];
baseAddress,
&array1d_indexes[0],
array1d_nDimensions
);
printf("SANITY CHECK: %d %d\n",val1,val2);
// 3 dimensions
int array3d[LEN][LEN][LEN];
int array3d_indexes[] = {2,3,4};
int array3d_nDimensions = 3;
baseAddress = &array3d[0][0][0];
for(i = 0; i < LEN*LEN*LEN; i++) { baseAddress[i] = i; }
val1 = array3d[2][3][4];
val2 = getValue_nDimensions( // Equivalent to: val1 = array3d[2][3][4];
baseAddress,
&array3d_indexes[0],
array3d_nDimensions
);
printf("SANITY CHECK: %d %d\n",val1,val2);
// 5 dimensions
int array5d[LEN][LEN][LEN][LEN][LEN];
int array5d_indexes[] = {2,3,4,5,6};
int array5d_nDimensions = 5;
baseAddress = &array5d[0][0][0][0][0];
for(i = 0; i < LEN*LEN*LEN*LEN*LEN; i++) { baseAddress[i] = i; }
val1 = array5d[2][3][4][5][6];
val2 = getValue_nDimensions( // Equivalent to: val1 = array5d[2][3][4][5][6];
baseAddress,
&array5d_indexes[0],
array5d_nDimensions
);
printf("SANITY CHECK: %d %d\n",val1,val2);
return 0;
}
输出:
SANITY CHECK: 2 2
SANITY CHECK: 234 234
SANITY CHECK: 23456 23456
答案 2 :(得分:2)
术语'row major'和'column major'不能很好地转化为第三维。存储的下一个元素来自当前行或当前列的概念分解。这听起来有点滑稽,但这成为“深度主要”与“宽度主要”排序。每个后续元素不再是单个条目,而是一个完整的二维矩阵。
/ X / +---+---+---+ / / / /| +---+---+---+-+------- | 1 | 5 | 9 |/| Y +---+---+---+ + | 2 | 6 | A |/| +---+---+---+ + | 3 | 7 | B |/| +---+---+---+ + | 4 | 8 | C |/ +---+---+---+
因此,存储器在存储器中依次具有1,2,3,4,5,6,7,8,9,10,11,12,13。这是经典的列主要排序。通过将D条目放在标记为X的位置,您没有改变矩阵具有colum主要排序的事实。如果将D条目放在Y所在的位置,您仍然没有改变使用列主要排序的事实。如果您使用深度主要(X)或宽度主要(Y)排序,那么您决定放置下一个块将会影响。如你所知,这些是等价的,但称之为某些东西可能有助于你编写方程式:
[假设基于数组]
您可以通过以下等式访问二维柱主要元素的内存位置:
MatrixOffset = base + (sizeof(entry) * ((4 * ( column - 1 )) + (row - 1)))
此地址将使用深度或宽度进行调整,这完全是术语问题。
TotalOffset = MatrixOffset + (sizeof(entry) * ((4 * 3) * (depth - 1)))
或强>
TotalOffset = MatrixOffset + (sizeof(entry) * ((4 * 3) * (width - 1)))
常数4和3可能是变量COLUMNS和ROWS。
不要问我关于第4维的事情!
答案 3 :(得分:0)
基本上在行主要的3D arrray中E.g Arr [3] [4] [5] 当你想要Arr [0]时,它会像上面那样寻找图像的前切片 Arr [1]第二个切片,依此类推。 所以Arr [0]意味着尺寸为[4] [5]的二维数组,所以每个Arr [x]对应x *(4 * 5) 现在关于Arr [x] [y]可以被认为是一个大小为[1]的一维数组,其位置是上图中顶视图的[x] [y] 所以当我们想要Arr [x] [y] = x *(4 * 5)+ y *(5)时 现在Arr [x] [y] [z]是深度为z的Arr [x] [y]的特定元素 编曲[X] [Y] [Z] = X *(4 * 5)+ Y * 5 + Z 现在根据你想要存储在数组中的数据类型的大小,偏移量可以乘以大小得到地址相对于开始
答案 4 :(得分:0)
当我问这个问题时,我希望找到一些好的三维数组示例。特别是代码示例。由于我没有找到任何可以理解的东西,我决定创建一个小C程序来帮助显示这个概念。它在3x4x5阵列中使用相同的测试数据。它还包括5x5x5阵列的测试数据。它从行主阵列创建列主阵列,以便验证偏移计算。
数组偏移方法是:
//
// Arrays.cpp :
// Purpose: Display rowMajor & colMajor data and calculations.
//
#include "stdafx.h"
#define _show_Arrays 1 // 1=display rowMajor & colMajor arrays
#define _square_array 0 // 1=use arr[5][5][5], 0=use arr[3][4][5]
#if (_square_array == 1)
const int depthSz = 5;
const int rowSz = 5;
const int colSz = 5;
/*
+---+---+---+---+---+
|x00|x01|x02|x03|x04|
+---+---+---+---+---+
|x05|x06|x07|x08|x09|
+---+---+---+---+---+
|x0A|x0B|x0C|x0D|x0E|
+---+---+---+---+---+
|x0F|x10|x11|x12|x13|
+---+---+---+---+---+
|x14|x15|x16|x17|x18|
+---+---+---+---+---+
slice x
*/
short row_arr[depthSz][colSz][rowSz] = {
{ /* slice 0 */
{0x000,0x001,0x002,0x003,0x004},
{0x005,0x006,0x007,0x008,0x009},
{0x00A,0x00B,0x00C,0x00D,0x00E},
{0x00F,0x010,0x011,0x012,0x013},
{0x014,0x015,0x016,0x017,0x018}},
{ /* slice 1 */
{0x100,0x101,0x102,0x103,0x104},
{0x105,0x106,0x107,0x108,0x109},
{0x10A,0x10B,0x10C,0x10D,0x10E},
{0x10F,0x110,0x111,0x112,0x113},
{0x114,0x115,0x116,0x117,0x118}},
{ /* slice 2 */
{0x200,0x201,0x202,0x203,0x204},
{0x205,0x206,0x207,0x208,0x209},
{0x20A,0x20B,0x20C,0x20D,0x20E},
{0x20F,0x210,0x211,0x212,0x213},
{0x214,0x215,0x216,0x217,0x218}},
{ /* slice 3 */
{0x300,0x301,0x302,0x303,0x304},
{0x305,0x306,0x307,0x308,0x309},
{0x30A,0x30B,0x30C,0x30D,0x30E},
{0x30F,0x310,0x311,0x312,0x313},
{0x314,0x315,0x316,0x317,0x318}},
{ /* slice 4 */
{0x400,0x401,0x402,0x403,0x404},
{0x405,0x406,0x407,0x408,0x409},
{0x40A,0x40B,0x40C,0x40D,0x40E},
{0x40F,0x410,0x411,0x412,0x413},
{0x414,0x415,0x416,0x417,0x418}}
};
#else
const int depthSz = 3;
const int rowSz = 4;
const int colSz = 5;
/*
+---+---+---+---+
|000|001|002|003|
+---+---+---+---+
|004|005|006|007|
+---+---+---+---+
|008|009|00A|00B|
+---+---+---+---+
|00C|00D|00E|00F|
+---+---+---+---+
|010|011|012|013|
+---+---+---+---+
slice x
*/
short row_arr[depthSz][colSz][rowSz] = {
{ /* slice 0 */
{0x000,0x001,0x002,0x003},
{0x004,0x005,0x006,0x007},
{0x008,0x009,0x00A,0x00B},
{0x00C,0x00D,0x00E,0x00F},
{0x010,0x011,0x012,0x013}},
{ /* slice 1 */
{0x100,0x101,0x102,0x103},
{0x104,0x105,0x106,0x107},
{0x108,0x109,0x10A,0x10B},
{0x10C,0x10D,0x10E,0x10F},
{0x110,0x111,0x112,0x113}},
{ /* slice 2 */
{0x200,0x201,0x202,0x203},
{0x204,0x205,0x206,0x207},
{0x208,0x209,0x20A,0x20B},
{0x20C,0x20D,0x20E,0x20F},
{0x210,0x211,0x212,0x213}}
};
#endif
short col_arr[depthSz*colSz*rowSz]; //
char *calc_RowMajor(char *Base, int elemSz, int depth_idx, int row_idx, int col_idx)
{ // row major slice is navigated by rows
char *address;
int lbound = 0; // lower bound (0 for zero-based arrays)
address = Base /* use base passed */
+ ((depth_idx-lbound)*(colSz*rowSz*elemSz)) /* select slice */
+ ((row_idx-lbound)*rowSz*elemSz) /* select row */
+ ((col_idx-lbound)*elemSz); /* select col */
return address;
}
char *calc_ColMajor(char *Base, int elemSz, int depth_idx, int col_idx, int row_idx)
{ // col major slice is navigated by columns
char *address;
int lbound = 0; // lower bound (0 for zero-based arrays)
int pageSz = colSz*rowSz*elemSz;
int offset;
offset = (col_idx-lbound)*(colSz*elemSz) /* select column */
+ (row_idx-lbound)*(elemSz); /* select row */
if (offset >= pageSz)
{ // page overflow, rollover
offset -= (pageSz-elemSz); /* ajdust offset back onto page */
}
address = Base /* use base passed */
+ ((depth_idx-lbound)*pageSz) /* select slice */
+ offset;
return address;
}
void disp_slice(char *pStr, short *pArr,int slice,int cols, int rows)
{
printf("== %s slice %d == %p\r\n",pStr, slice,pArr+(slice*rows*cols));
for(int x=0;x<rows;x++)
{
for(int y=0;y<cols;y++)
printf("%03X ",*(pArr+(slice*rows*cols)+(x*cols)+y));
printf("\r\n");
}
}
int _tmain(int argc, _TCHAR* argv[])
{
// initialize col based array using row based array data
{ // convert row_arr into col_arr
short *pSrc = &row_arr[0][0][0];
short *pDst = &col_arr[0];
for(int d=0;d<depthSz;d++)
for(int r=0;r<rowSz;r++)
for(int c=0;c<colSz;c++)
{
*pDst++ = *(pSrc+((d*rowSz*colSz)+(c*rowSz)+r));
}
}
printf("Using Array[%d][%d][%d]\r\n",depthSz,rowSz,colSz);
#if (_show_Arrays == 1)
{ for(int x=0;x<depthSz;x++) {disp_slice("rowMajor",&row_arr[0][0][0],x,rowSz,colSz);}}
{ for(int x=0;x<depthSz;x++) {disp_slice("colMajor",&col_arr[0],x,rowSz,colSz);}}
#endif
int d = 2; // depth
int r = 3; // row
int c = 4; // column
for(d=0;d<depthSz;d++)
{
c = r = d; // simple access test pattern arr[0][0][0],arr[1][1][1],arr[2][2][2],...
{ // retrieve Array element
printf(" row_arr[%d][%d][%d] = %x\t",d,r,c,row_arr[d][r][c]);
printf("&row_arr[%d][%d][%d] = %p\r\n",d,r,c,&row_arr[d][r][c]);
}
{ // retrieve RowMajor element
short *pRowMajor = (short*)calc_RowMajor((char*)&row_arr[0][0][0],sizeof(short),d,r,c);
printf("calc_RowMajor(%d,%d,%d) = %x\t\t",d,r,c,*pRowMajor);
printf("pRowMajor = %p\r\n",pRowMajor);
}
{ // retrieve ColMajor element
short *pColMajor = (short*)calc_ColMajor((char*)&col_arr[0],sizeof(short),d,c,r);
printf("calc_ColMajor(%d,%d,%d) = %x\t\t",d,r,c,*pColMajor);
printf("pColMajor = %p\r\n",pColMajor);
}
} // for
getchar(); // just to hold the console while looking at the information
return 0;
}
答案 5 :(得分:0)
k维数组的公式是
k-1 n
i + ∑ i * ∏ c
0 n=1 n m=0 m
其中i下标n是n = {0,1,2,... k-1}的维数n的索引 和c下标m是m = {0,1,2,... k-2}的维数m的基数。
可以在此处找到PNG格式的更好的公式呈现:
http://modula-2.info/m2r10/pmwiki.php/Spec/LanguageReport#MultiDimensionalArrays