web-dev-qa-db-fra.com

calculs de décalage de tableau dans un tableau multidimensionnel (colonne vs ligne principale)

Un manuel que j'ai lu récemment a traité des tableaux de lignes majeures et de colonnes majeures. Le livre portait principalement sur les tableaux à 1 et 2 dimensions, mais ne traitait pas vraiment des tableaux à 3 dimensions. Je suis à la recherche de bons exemples pour renforcer ma compréhension de l'adressage d'un élément dans un tableau multidimensionnel à l'aide de tableaux de lignes et de colonnes.

 + - + - + - + | 
//// | | 
 + - + - + - + + | + --- + --- + --- + --- + 
//// |/| |//// /|
 + - + - + - + + + | + --- + --- + --- + --- + + 
//// |/|/| |//// /|/|
 + - + - + - + + + + + | + --- + --- + --- + --- + + + 
//// |/|/|/| |//// /|/|/|
 + - + - + - + + + + + + | + --- + --- + --- + --- + + + + + 
//// |/|/|/| | 000 | 001 | 002 | 003 |/|/|/| 
 + - + - + - + + + + + + | + --- + --- + --- + --- + + + + + 
 | 00 | 01 | 02 |/|/|/|/| | 004 | 005 | 006 | 007 |/|/|/| 
 + - + - + - + + + + + | + --- + --- + --- + --- + + + + + 
 | 03 | 04 | 05 |/|/|/| | 008 | 009 | 00A | 00B |/| Gite | /
 + - + - + - + + + + | + --- + --- + --- + --- + + + 
 | 06 | 07 | 08 |/|/| | 00C | 00D | 00E | 00F |/| /
 + - + - + - + + | + --- + --- + --- + --- + + 
 | 09 | 0A | 0B |/| | 010 | 011 | 012 | 013 | /
 + - + - + - + | + --- + --- + --- + --- + 
 arr [5] [3] [4] | arr [3] [4] [5] 

REMARQUE: Question originale mal représentée arr [3] [4] [5]. J'ai appris que l'indice initial représentait la profondeur. Les données ont été corrigées pour refléter la représentation de tableau souhaitée.

 Exemple de données hexadécimales 
 + --- + --- + --- + --- + + --- + --- + --- + --- + --- + + - - + --- + --- + --- + 
 | 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 | 
 + --- + --- + --- + --- + + --- + --- + --- + --- + --- + + - - - + --- + --- + --- + 
 tranche 0 tranche 1 tranche 2 
 
 court Arr [3] [4] [5]; // suppose que le tableau est rempli de données de test hexadécimales 
 
 arr [1] [2] [3] = 0x10B utilisez la tranche 1, rangée 2, colonne 3 
 arr [2] [3] [4] = 0x210, utilisez la tranche 2, ligne 3, colonne 4 
 Correspond à la ligne 4, colonne 0 
 

rangée majeure
[En stock] 20A, 20B, 20C, 20D, 20E, 20F, 210,211,212,213}

major de colonne {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,105,109,109,10D, 111,1010, , 10B, 10F, 113, 200,204,208,20C, 210,201,205,209,20D, 211,202,206,20A, 20E, 212,203,207,20B, 20F, 213}

 Décalage de calcul pour arr [1] [2] [3] en utilisant le décalage principal de ligne? 
 Décalage de calcul pour arr [1] [2] [3] en utilisant le décalage principal de colonne? 
24
mrwes

Lorsque j'ai posé cette question, j'espérais trouver de bons exemples de tableaux en 3 dimensions. Surtout des exemples de code. N'ayant rien trouvé de compréhensible, j'ai décidé de créer un petit programme en C pour aider à afficher le concept. Il utilise les mêmes données de test dans un tableau 3x4x5. Il comprend également des données de test pour un tableau 5x5x5. Il crée un tableau majeur de colonne à partir du tableau principal de ligne afin que les calculs de décalage puissent être vérifiés.

Les méthodes de décalage de tableau sont:

  • char * calc_RowMajor (char * Base, int elemSz, int depth_idx, int row_idx, int col_idx)
  • char * calc_ColMajor (char * Base, int elemSz, int depth_idx, int col_idx, int row_idx)

    J'ai ajouté des commentaires dans le code, le cas échéant, pour clarifier le rôle du code.

    
    //
    // 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;
    }
    
  • 0
    mrwes

    Ne vous contraignez pas artificiellement en vous concentrant sur 3 dimensions et 2 dimensions. Au lieu de cela concentrez-vous sur l'apprentissage de l'expression permettant d'adresser des tableaux à n dimensions

    Exprimer un adressage n-dimensionnel solidifierait votre compréhension sur ce sujet et serait plus facile de se souvenir d'une formule plutôt que de formules séparées pour l'adressage 2D et 3D.


    Voici ma tentative d'adressage n-dimensionnel:

    #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;
    }
    

    Sortie:

    SANITY CHECK:     2     2
    SANITY CHECK:   234   234
    SANITY CHECK: 23456 23456
    
    10
    Trevor Boyd Smith

    Je verrais le ordre de rangée-majeur article Wikipedia. Il y a une section qui décrit les dimensions supérieures à 2. Il y a aussi un bon article ici . Cet article donne la formule suivante pour un tableau à trois dimensions utilisant une présentation en lignes majeures:

    Address = Base + ((depthindex*col_size+colindex) * row_size + rowindex) * Element_Size
    

    Pour un tableau 3D: tapez A [profondeur] [col] [ligne]. La base est le décalage de départ du tableau. De plus, les variables de taille sont les différentes tailles de chaque dimension. La variable Element_Size indique la taille de tout type de composition du tableau.

    Supposons que vous ayez un tableau ligne-majeur a [4] [6] [5] composé d'entiers C++ standard. Pour calculer le décalage d'un 1 [3] 2 , vous devez insérer les nombres suivants dans la formule:

    Address = Base + ((1 * 6 + 3) * 5 + 2) * 4
    

    Pour un tableau à 3 dimensions ayant une disposition colonne-majeur, l'équation serait plutôt la suivante:

    Address = Base + ((rowindex*col_size+colindex) * depth_size + depthindex) * Element_Size
    

    Les numéros que vous utiliseriez pour l'exemple ci-dessus en utilisant une disposition colonne-majeur seraient les suivants:

    Address = Base + ((2 * 6 + 3) * 4 + 1) * 4
    
    10
    Cory Walker

    Les termes "ligne majeure" et "colonne majeure" ne se traduisent pas bien en une troisième dimension. La notion selon laquelle l'élément suivant stocké provient de la ligne ou de la colonne en cours est décomposée. Cela semble un peu comique, mais cela devient un ordre «profondeur majeure» contre un ordre «largeur majeure». Chaque élément suivant n'est plus une entrée unique mais une matrice complète à deux dimensions.

    /X 
    /
     + --- + --- + --- + 
    //// | 
     + --- + --- + --- + - + ------- 
     | 1 | 5 | 9 |/| Y 
     + --- + --- + --- + + 
     | 2 | 6 | A |/| 
     + --- + --- + --- + + 
     | 3 | 7 | B |/| 
     + --- + --- + --- + + 
     | 4 | 8 | C | /
     + --- + --- + --- + 
     
    

    Ainsi, la mémoire aurait littéralement 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 en mémoire séquentiellement. C’est l’ordre des colonnes classiques. En plaçant l'entrée D à la position marquée X, vous n'avez pas modifié le fait que votre matrice est en ordre de priorité. Si vous placez l'entrée D où le Y est, vous n'avez toujours pas changé le fait que vous utilisez le classement par colonne. L'emplacement où vous décidez de placer le prochain bloc aura une incidence sur le fait que vous utilisiez l'ordre de profondeur majeure (X) ou de largeur majeure (Y). Comme vous le savez bien, ce sont des équivalents, mais appeler quelque chose peut vous aider à écrire des équations:

    [0 Bases supposées]  

    Vous accédez à l'emplacement de la mémoire d'un élément majeur de colonne à deux dimensions via l'équation: 

    MatrixOffset = base + (sizeof(entry) * ((4 * ( column - 1 ))   +  (row - 1)))
    

    Cette adresse serait ajustée en fonction de la profondeur ou de la largeur, tout était une question de terminologie.

    TotalOffset = MatrixOffset + (sizeof(entry) * ((4 * 3) * (depth - 1))) 
    

    OU

    TotalOffset = MatrixOffset + (sizeof(entry) * ((4 * 3) * (width - 1))) 
    

    Les constantes 4 et 3 seraient probablement les variables COLUMNS et ROWS.

    Ne me demandez pas à propos du 4ème dimention!

    2
    ojblass

    En gros, dans un tableau 3D avec une rangée majeure, par exemple Arr Arr [3] [4] [5] Lorsque vous voulez Arr [0], la partie avant de l'image est recherchée comme ci-dessus Arr [ 1] deuxième tranche et ainsi de suite. Donc Arr [0] désigne un tableau 2D de taille [4] [5], ainsi chaque Arr [x] correspond à x * (4 * 5) Maintenant, à propos de Arr [x] [y], on peut penser à un tableau 1D de taille [5] dont la position est [x] [y] à partir de la vue de dessus dans l'image ci-dessus Alors quand on veut Arr [x ] [y] = x * (4 * 5) + y * (5) maintenant Arr [x] [y] [z] est l’élément spécifique d’Arr [x] [y] à la profondeur z Arr [x] [y] [z] = x * (4 * 5) + y * 5 + z Maintenant sur la base de la taille du type de données que vous souhaitez stocker dans le tableau , le décalage peut être multiplié par la taille obtenir l'adresse par rapport au début

    0
    bajrangbali

    La formule pour les tableaux de dimension k est

        k-1       n
    i  + ∑  i  *  ∏  c
     0  n=1  n   m=0  m
    

    où i indice n est l'indice de la dimension n pour n = {0, 1, 2, ... k-1} et c indice m est la cardinalité de la dimension m pour m = {0, 1, 2, ... k-2}.

    Un rendu plus agréable de la formule au format PNG peut être trouvé ici:

    http://modula-2.info/m2r10/pmwiki.php/Spec/LanguageReport#MultiDimensionalArrays

    0
    trijezdci