2015-11-03 9 views
5

Basit veri türlerini bilinen boyuttaki dizide belirli konumlara taşımanın en hızlı yolu nedir?Dizideki basit veri türlerini belirli konumlara taşımak için en hızlı yol

bir int olarak depolanan bir oyun tahtası döner vardı özel durum [9]
[0,1,2,3,4,5,6,7,8] Her döner gereken bu dizilerin bir vektör, vardı kullanımım durumda [6,3,0,7,4,1,8,5,2]


olur.

Kurulu Düzen:

board1|corners|centers 
0 1 2 | 0 2 | 1 
3 4 5 |  | 3 5 
6 7 8 | 6 8 | 7 

board2|corners|centers 
6 3 0 | 6 0 | 3 
7 4 1 |  | 7 1 
8 5 2 | 8 2 | 5 

Ben ile geldi en hızlı yöntemi dizi girdileri atamak ve sonra geri belleği kopyalamak için bir ortak değişken yaratmaktı. o


Hem nispeten olan (tek iş parçacığı üzerinde yarısından daha az hız) çok daha yavaş saatler ..though

int layout[9]; 
int pub_layout[9]; 

#include <cstring> // for std::memcpy 
void rotate(int layout[]) 
{ 
    pub_layout[4] = layout[4]; // center 

    pub_layout[0] = layout[6]; // corner four 
    pub_layout[6] = layout[8]; 
    pub_layout[8] = layout[2]; 
    pub_layout[2] = layout[0]; 

    pub_layout[1] = layout[3]; // center four 
    pub_layout[3] = layout[7]; 
    pub_layout[7] = layout[5]; 
    pub_layout[5] = layout[1]; 

    std::memcpy(layout,pub_layout,sizeof(pub_layout)); 
} 

Ben
int[] b = new int[] {b[6], b[3], b[0], b[7], b[4], b[1], b[8], b[5], b[2]};
önerir benzer bir soru here gördük Bu hızlı yöntem değilse hızlı (see a test here)

, nedir?
Algoritmanın hem C hem de C++ 'da aynı olacağından şüpheleniyorum. Eğer memcpy çağrıyı ve [4] [4] atama kazanç bu biriyle

+0

Gönderdiğiniz test koduyla ilgili birkaç sorun. 'Rotate2()' işlevi, döndürme() 'değilken dinamik bellek ayırmalarını (bu örnek koddaki tüm sızıntı, btw) içerir. Yani, rotate2() 'nin daha yavaş olması şaşırtıcı değildir. [Burada] (http://coliru.stacked-crooked.com/a/bc6b9bc5ecfd42ce) C++ 11 kapsayıcılar ve algoritmalar kullanan biraz değiştirilmiş bir koddur. Bu durumda, rotate() ve rotate2(), benzerdir ve herhangi bir dinamik bellek ayırımı içermez. – crayzeewulf

+0

, _not_ satır sırasına kaydetmeyi düşündünüz mü? Eğer onları 0, 1, 2, 5, 8, 7, 6, 3, 4 'sıralarında sakladıysanız ve' int 'yerine 'char' kullandıysanız, kartın döndürülmesi sadece ilk 8 elemanın 3 element kayması gerektirir. son elemanı (konum 4) değişmez bırakarak. – Alnitak

+0

daha da fazlası, tek bir 'long'da saklanan 8 eleman ile rotasyon iki 24-bit vardiya işlemi ve biraz bit maskeleme ile elde edilebilir. – Alnitak

cevap

4

. putAside değişkenine iki ödevi kaybedersiniz. Yani kesinlikle biraz daha hızlı.

int layout[9]; 
int putAside; 

void rotate(int[] layout) 
{ 
    putAside = layout[0]; 
    layout[0] = layout[6]; // corner four 
    layout[6] = layout[8]; 
    layout[8] = layout[2]; 
    layout[2] = putAside; 

    putAside = layout[1]; 
    layout[1] = layout[3]; // center four 
    layout[3] = layout[7]; 
    layout[7] = layout[5]; 
    layout[5] = putAside; 
} 
+1

Bu cevabı beğeniyorum, ancak emin olmanın tek yolu (veya başka bir yaklaşım) daha hızlı ölçüm yapmaktır. Ancak bu en temiz yaklaşımdır - ve bir derleyicinin çılgın gibi optimize etmek için adil bir fırsatı vardır. Ayrıca, bir statik yapmak için çok az bir değer olduğu için, putAside'ı yerel (otomatik) bir değişken yapmak isteyebilir. Ayrıca, OP'nin hatasını çoğalttığınızı da unutmayın - "int [] düzeni" türü, bir işlev parametresi için geçerli bir tür değil. – Peter

+0

Bu benim sistemimde -O3 ile çok daha hızlı (2.6x) ve bayrak olmadan derlendiğinde biraz daha hızlı (% 14)! @ Peter'ın önerisi yine -O3 (% 9) ile biraz daha hızlı ve bu cevapla karşılaştırıldığında (% 5) biraz daha yavaştır. – ti7

1

en hızlı şekilde çok sıkı bir döngüde işlemci önbellek kullanımı muhtemelen:

void rotate(int in[3][3], int out[3][3]) 
{ 
    int i, j, k; 
    for (i=0,k=2;i<3;i++,k--) 
     for (j=0;j<3;j++) 
      out[j][k] = in[i][j]; 
} 

Not: board[9]board[3][3] eşdeğerdir ve bitişik 3 ints 3 dizileri olarak 9 int'leri görmektedir bellek, böylece isterseniz:

void rotate(int in[9], int out[9]) 
{ 
    int i, j, k; 
    for (i=0,k=2;i<3;i++,k--) 
     for (j=0;j<3;j++) 
      out[j*3+k] = in[i*3+j]; 
} 

o in ve out size daha sonra, aynı olabileceği gerekli olmalı Eğer herhangi bir dönüşümü uygulamak için daha esnek bir şekilde istiyorsanız

void rotate(int in[9], int out[9]) 
{ 
    int tmp[9]; 
    int i, j, k; 
    for (i=0,k=2;i<3;i++,k--) 
     for (j=0;j<3;j++) 
      tmp[j*3+k] = in[i*3+j]; 
    //memcpy(out,tmp, sizeof(tmp)); // use this... 
    for(i=0;i<9;i++) out[i]=tmp[i]; //..or this, whichever clocks faster 
} 
+0

'rotate()' ikinci sürümünüzdeki sorun, ilkine farklı türde argümanlar kabul etmesidir. Bu yüzden, arayan için, değiştirilmesinde tam bir düşüş değildir - derleyiciyi kabul etmeye zorlamak için bir tür dönüşüm gerekli olacaktır. – Peter

+0

@Peter, Ben sadece bir int [9] 'kurulu olarak kullanan OPs başlangıç ​​noktası eşleştirmek için farklı bir sürüm veriyoruz. Kullanmak istediği ona kadar. –

+0

Bu, -O3 ile çok hızlıdır (Peter'ın sistemimde Joël'in yaptığı değişiklikten% 12 daha hızlıdır), ama ne yazık ki 0 1 2 3 4 5 6 7 8' olurken 0 1 6 3 4 3 6 3 6' Aynı parametreyi döndürdü (döndürme (a, a); – ti7

1

, aşağıdaki gibi bir şey de oldukça hızlı olacaktır:

template <int _1, int _2, int _3, int _4, int _5, int _6, int _7, int _8, int _9> 
struct transfomer { 
    board& _in; 
    operator board() const { 
     return { _in[_1], _in[_2], _in[_3], _in[_4], _in[_5], _in[_6], _in[_7], _in[_8], _in[_9] }; 
    } 
}; 

void rotate3(board& layout) { 
    layout = transfomer<6, 3, 0, 7, 4, 1, 8, 5, 2>{layout}; 
} 
İşte

Ben board tanımladığınız:

aşağıdaki kullanmalıdır
typedef array<int, 9> board; 

Ve evet, örtük dönüştürme işlecine dayanır (normalde kötü IMO'dur, ancak burada yararlıdır).) (NOT: Testinizi, array<> ile çalışmak için biraz uyarladım ve aynı testi yürütmek, yukarıdaki kodun, @Joel'den el ile taşınan çözümden biraz daha iyi değilse, yaklaşık olarak aynı olduğunu gösterir)

İlgili konular