2B bir diziyi 1 boyutlu bir diziye eşleyin


91

Bir 1B dizisi ile bir 2D diziyi temsil etmek istiyorum. Bir işlev iki göstergeyi (x, y) ve saklanacak değeri iletir. Bu iki gösterge, 1B dizisinin tek bir öğesini temsil edecek ve buna göre ayarlayacaktır. 1D dizisinin arrayWidth × arrayHeight boyutunda olması gerektiğini biliyorum, ancak her bir öğeyi nasıl ayarlayacağımı bilmiyorum.

Örneğin, (2,4,3) 'ü (4,2,3)' ten nasıl ayırt edebilirim? Diziyi x * y olarak ayarlamayı denedim, ancak 2 * 4 ve 4 * 2 dizide aynı nokta ile sonuçlanacak ve farklı olmalarına ihtiyacım var.

Yanıtlar:


166

Dizi öğelerinin satır sırasına mı yoksa sütun sırasına göre mi depolanacağına karar vermeniz ve ardından bu konuda tutarlı olmanız gerekir. http://en.wikipedia.org/wiki/Row-major_order

C dili, Çok boyutlu diziler için satır sırasını kullanır

Bunu tek boyutlu bir dizi ile simüle etmek için, satır indeksini genişlikle çarparsınız ve sütun indeksini şöyle eklersiniz:

 int array[width * height];

 int SetElement(int row, int col, int value)
 {
    array[width * row + col] = value;  
 }

7
Bu cevabın daha net olduğunu düşünüyorum, özellikle yeni başlayanlar için fonksiyonları tek satırda yazmamak daha iyidir ... !! Zaten kötü bir pratik .. :)
Lipis

3
Bu cevap, uygun çok boyutlu dizi desteğine sahip olmayan bir derleyiciniz (ör. Gömülü sistemler) olduğunda da yararlıdır
Alex Marshall

1
Aynı soruyu kaç kişinin doğru cevaplayabileceği şaşırtıcı, ancak sadece bir tanesi bunu anlaşılması kolay bir şekilde söylüyor. Bu, olabildiğince basit bir cevap. Bununla birlikte, John buna iyi bir cevap veren tek kişidir. Geri kalan her şey, yalnızca cevabı zaten bilenler tarafından kolayca anlaşılabilecek çöpler. Gerçekten uzaylı yerine İngilizce konuştuğun için teşekkürler John. Sadece bazı insanların öğretimde ne kadar kötü olduğunu ve John Knoeller gibi iyi öğretmenlerin nasıl basitleştirme ve herkesten daha etkili iletişim kurmayı bildiklerini göstermeye gider.
user2948630

6
Bu eşlemenin nasıl ters çevrileceğini göstermek iyi olur: 1D dizisinin dizini ise alphave 2D dizinin Nendekslerle her iki yönde de boyutu x, yvarsa, @JohnKnoeller'a göre alpha=x+N*y,. Bunu tersine çevirmenin yolu ayar x=alpha%Nve olacaktır y= (alpha-alpha%N)/N.
Tim

Buraya neredeyse her gün geliyorum!
Felipe Gutierrez

23

2B dizi indekslerinin 1D dizi indeksine yeniden hesaplanması için tipik formül

index = indexX * arrayWidth + indexY;

Alternatif olarak kullanabilirsiniz

index = indexY * arrayHeight + indexX;

( arrayWidthX ekseni arrayHeightboyunca ve Y ekseni boyunca ölçüldüğünü varsayarak )

Elbette, alternatif benzersiz eşlemeler sağlayan birçok farklı formül bulunabilir, ancak normalde buna gerek yoktur.

C / C ++ dillerinde yerleşik çok boyutlu diziler bellekte depolanır, böylece son dizin en hızlı şekilde değişir, yani bir dizi için

int xy[10][10];

öğesinin xy[5][3]hemen ardından xy[5][4]bellekte gelir. Bu kuralı da takip etmek isteyebilirsiniz, bu iki formülden hangisini "son" olarak kabul ettiğinize bağlı olarak yukarıdaki iki formülden birini seçin (X veya Y).


17

Örnek: SIZE_X ve SIZE_Y boyutlu 2D bir diziyi temsil etmek istiyoruz. Bu, MAXX boyutunda MAXY ardışık satırımız olacağı anlamına gelir. Dolayısıyla set işlevi

void set_array( int x, int y, int val ) { array[ x * SIZE_Y + y ] = val; }

Getirisi şöyle olacaktır:

int get_array( int x, int y ) { return array[ x * SIZE_Y + y ]; }

1
Sizin MAXXve MAXYmaksimum değerleri nedeniyle değerleri karışıklığa, adlandırılması xve yvardır MAXX - 1ve MAXY - 1sırasıyla. Belki SIZE_Xve SIZE_Ydaha iyi olabilir mi?
cafe

3
[y * maxx + x] sütun sırasıdır, satır sırası değil. Bu matlab çalışır yoldur, ama normalde C. işi değildir yolu diziler ise
John Knoeller

@everyone: Verilere dokunmadığınız, ancak tamamen bu iki get / set işlevini kullanmadıkça ve aynı formülü kullanmadıkça, bunu BU veya ŞU gibi yapabilirsiniz. (Garantili!)
imacake

Burada bir makro daha uygun olabilir, bu nedenle düşük seviyeli bir veri erişimi olması gereken şey üzerine gereksiz fonksiyon çağrılarını
yığmazsınız

Kodun bir sınıf üyesi olduğu varsayıldığında, bu kod satır içi olacaktır. Aksi takdirde, açık satır içi bir makrodan ÇOK daha iyidir.
Kornel Kisielewicz

7

Diğerleri satır sırasına göre C haritalarını söyledi

   #include <stdio.h>

   int main(int argc, char **argv) {
   int i, j, k;
   int arr[5][3];
   int *arr2 = (int*)arr;

       for (k=0; k<15; k++) {
          arr2[k] = k;
          printf("arr[%d] = %2d\n", k, arr2[k]);
       }

       for (i=0; i<5; i++) {
         for (j=0; j< 3; j++) {
            printf("arr2[%d][%d] = %2d\n", i, j ,arr[i][j]);
         }
       } 
    } 

Çıktı:

arr[0] =  0
arr[1] =  1
arr[2] =  2
arr[3] =  3
arr[4] =  4
arr[5] =  5
arr[6] =  6
arr[7] =  7
arr[8] =  8
arr[9] =  9
arr[10] = 10
arr[11] = 11
arr[12] = 12
arr[13] = 13
arr[14] = 14
arr2[0][0] =  0
arr2[0][1] =  1
arr2[0][2] =  2
arr2[1][0] =  3
arr2[1][1] =  4
arr2[1][2] =  5
arr2[2][0] =  6
arr2[2][1] =  7
arr2[2][2] =  8
arr2[3][0] =  9
arr2[3][1] = 10
arr2[3][2] = 11
arr2[4][0] = 12
arr2[4][1] = 13
arr2[4][2] = 14

3

ana satır örneğini kullanarak:

A(i,j) = a[i + j*ld]; // where ld is the leading dimension
                      // (commonly same as array dimension in i)

// matrix like notation using preprocessor hack, allows to hide indexing
#define A(i,j) A[(i) + (j)*ld]

double *A = ...;
size_t ld = ...;
A(i,j) = ...;
... = A(j,i);

1

Verileri kullanılan dillerde alınabilecek şekilde saklamak önemlidir. C-dili, 0'dan boyut-1'e kadar her indeksle birlikte ana satır sırasına göre depolar (ilk satırın tümü önce gelir, sonra ikinci satırın tümü, ...). Dolayısıyla, x [2] [3] dizisinin sırası x [0] [0], x [0] [1], x [0] [2], x [1] [0], x [1] [ 1], x [1] [2]. Yani C dilinde, x [i] [j], 1 boyutlu dizi girişi x1dim [i * 3 + j] ile aynı yerde saklanır. Veriler bu şekilde depolanırsa, C dilinde geri getirilmesi kolaydır.

Fortran ve MATLAB farklıdır. Sütun ana sırasına göre depolarlar (ilk sütunun tamamı önce gelir, sonra ikinci satırın tamamı, ...) ve her dizin 1'den boyutuna kadar çalışır. Yani endeks sırası C'nin tersidir ve tüm endeksler 1 büyüktür. Verileri C dil sırasına göre kaydederseniz, FORTRAN X_C_language [i] [j] 'yi X_FORTRAN (j + 1, i + 1) kullanarak bulabilir. Örneğin, X_C_language [1] [2], X_FORTRAN (3,2) 'ye eşittir. 1 boyutlu dizilerde, bu veri değeri X1dim_C_language [2 * Cdim2 + 3] 'de, X1dim_FORTRAN (2 * Fdim1 + 3 + 1) ile aynı konumdadır. Cdim2 = Fdim1 olduğunu unutmayın çünkü indislerin sırası tersine çevrilmiştir.

MATLAB, FORTRAN ile aynıdır. Ada, normalde 1'de başlayan endeksler haricinde C ile aynıdır. Herhangi bir dil, bu C veya FORTRAN siparişlerinden birinde endekslere sahip olacak ve endeksler 0 veya 1'den başlayacak ve depolanan verilere ulaşmak için buna göre ayarlanabilecektir.

Bu açıklama kafa karıştırıcıysa özür dilerim, ancak bence bir programcının bilmesi doğru ve önemli.


-2

Yerinde basit bir işaretçi ile 2d dizisine erişebilmelisiniz. [X] [y] dizisi, işaretçide p [0x * genişlik + 0y] [0x * genişlik + 1y] ... [0x * genişlik + n-1y] [1x * genişlik + 0y] vb. Şeklinde düzenlenecektir. .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.