Merulo Temat założony przez niniejszego użytkownika |
Przesuwanie wskaźników w tablicach dwuwymiarowych » 2016-09-05 17:28:49 Witam! Posiadam dość skomplikowany kod, tutaj jest uproszczona wersja: int tab[ 7 ][ 7 ]; int * p[ 7 ][ 7 ];
int k = 10;
for( int i = 0; i < 7; i++ ) { for( int j = 0; j < 7; j++ ) { tab[ i ][ j ] = k; k++; p[ i ][ j ] = & tab[ i ][ j ]; cout <<* p[ i ][ j ] << " "; } cout << endl; }
cout << "Przesuwam " << endl;
for( int i = 0; i < 7; i++ ) { for( int j = 0; j < 6; j++ ) { p[ i ][ j ] = p[ i ][ j + 1 ]; } }
for( int i = 0; i < 7; i++ ) { tab[ i ][ 0 ] = 99; p[ i ][ 6 ] = & tab[ i ][ 0 ]; }
for( int i = 0; i < 7; i++ ) { for( int j = 0; j < 7; j++ ) { cout <<* p[ i ][ j ] << " "; } cout << endl; }
Ten kod umożliwia przesuwanie wyświetlanej zawartości tablicy bez przesuwania danych (tab[x][y] = tab[x][y+1]). Związane jest to z faktem że przerzucanie danych obok jest zawolne. (w normalnej wersji to nie inty a spore ilości danych). Posiadam funkcje przesuwającą wyświetlanie w każdą stronę. Pewna sytuacja(mianowicie desynchronizacja) pojawia się gdy np. przesunę dane w lewo, do góry, a następnie w prawo. (w analogicznych sytuacjach też zachodzi desynchronizacja, np. Góra, lewo dół itp.) Wydaje mi się że problemem jest ta linijka: p[ i ][ j ] = p[ i ][ j + 1 ];
Ponieważ po pierwszych dwóch operacjach wskaźniki (zmienna p) wskazują na dane które są w innej kolumnie oraz rzędzie (zmienna tab) po kolejnym przesunięciu następuje desynchronizacja. Czy ktoś wie jak to rozwiązać? Tutaj jest graficzna reprezentacja problemu: https://s12.postimg.io/azqh6m1t9/image.png(jak powinno działać) https://s13.postimg.io/5pr2pb8t3/image.png(jak działa, w ostatnim etapie "w prawo", w prawej górnej części widać błąd |
|
mateczek |
» 2016-09-05 20:12:05 nadpisujesz zerowy rząd i tym samym go tracisz !!! p[ i ][ j ] = p[ i ][ j + 1 ];
|
|
Merulo Temat założony przez niniejszego użytkownika |
» 2016-09-05 21:01:19 Ale ja chce go stracić!!! Dane wczytywane są z plików. Dlatego "stracenie" jest ok, ponieważ na to miejsce lądują nowe dane (z pliku) które wyświetlane są w odpowiednim miejscu. Jeżeli program stwierdzi że dane który były kiedyś na 0 są potrzebne to je sobie wczyta. for( int i = 0; i < 7; i++ ) { tab[ i ][ 0 ] = 99; p[ i ][ 6 ] = & tab[ i ][ 0 ]; }
Tutaj widać wyraźnie że na zerowym rzędzie lądują nowe dane. Dopiero gdy wylądują nowe następuje wyświetlanie. Wydaje mi się, że rozwiązanie powinno być takie: Ale w jednym masz rację, ta linijka jest problemem p[ i ][ j ] = p[ i ][ j + 1 ];
Zakłada ona że odpowiednie wskaźniki ze sobą graniczą, a tak nie musi być. Pytanie jak je w takim razie przesunąć. |
|
mateczek |
» 2016-09-06 00:00:47 Swój kod najlepiej samemu prześledzić debuggerem w pracy krokowej i dowiedzieć się co źle robi. Ja kiedyś na potrzeby samo-dokształcania założyłem wątek odnośnie konstruktorów przenoszących i dla poćwiczenia postanowiłem napisać klasę macierzy 2D http://cpp0x.pl/forum/temat/?id=22952Macierz2D była w tym kodzie jednowymiarową macierzą z interfejsem 2D przeciążony operator. Do mojej starej klasy dopisałem funkcję przesuwania góra, dół, prawo, lewo void matrix::setOffset( int offw, int offk ) { if( offw > 0 ) offsetw = offw; else if( offw < 0 ) offsetw = wiersze + offw; else offsetw = 0; if( offk > 0 ) offsetk = offk; else if( offk < 0 ) offsetk = kolumny + offk; else offsetk = 0; }
Oraz zmodyfikowałem operator dostępu do elementu. Niewątpliwie wadą rozwiązania jest to że każdorazowo żądając dostępu do elementu wywołuje się ta funkcja int & operator ()( int w, int k ) { int index_w = w + offsetw; int index_k = k + offsetk; if( index_w >= wiersze ) index_w -= wiersze; if( index_k >= kolumny ) index_k -= kolumny; return tab[ index_w * kolumny + index_k ]; }
Całość kodu wygląda tak jak poniżej. Zdaję sobie sprawę, że dla pełnej funkcjonalności powinienem przerobić tą klasę na szablon, coby nie tylko INTy trzymać w niej było można. zobacz czy o taki efekt Ci chodziło ??? Poniżej kod gotowy do kompilacji! #include <iostream> using namespace std;
class matrix { int * tab = nullptr; int offsetw = 0, offsetk = 0; int wiersze = 0, kolumny = 0; public: friend ostream & operator <<( ostream & s, matrix & m ); matrix( int w, int k ) : wiersze( w ) , kolumny( k ) { cout << "jestem konstruktor" << endl; int rozmiar = w * k; tab = new int[ rozmiar ]; } matrix() { } ~matrix() { if( tab ) { delete[] tab; tab = nullptr; } } int & operator ()( int w, int k ) { int index_w = w + offsetw; int index_k = k + offsetk; if( index_w >= wiersze ) index_w -= wiersze; if( index_k >= kolumny ) index_k -= kolumny; return tab[ index_w * kolumny + index_k ]; } int row() { return wiersze; } int column() { return kolumny; } matrix & operator =( matrix && wzor ); matrix( matrix && wzor ); matrix( const matrix & wzor ); matrix operator *( matrix & m ); matrix & operator =( const matrix & wzor ); void setOffset( int ofw, int ofk ); };
matrix & matrix::operator =( matrix && wzor ) { cout << "jestem operator przenoszenia" << endl; std::swap( wzor.tab, tab ); std::swap( wiersze, wzor.wiersze ); std::swap( kolumny, wzor.kolumny ); return * this; } matrix::matrix( matrix && wzor ) { cout << "jestem konstruktor przenoszący" << endl; tab = wzor.tab; wiersze = wzor.wiersze; kolumny = wzor.kolumny; wzor.tab = nullptr; }
matrix::matrix( const matrix & wzor ) { cout << "jestem konstruktor kopiujący" << endl; wiersze = wzor.wiersze; kolumny = wzor.kolumny; int rozmiar = wiersze * kolumny; tab = new int[ rozmiar ]; for( int i = 0; i < rozmiar; i++ ) { tab[ i ] = wzor.tab[ i ]; } }
matrix & matrix::operator =( const matrix & wzor ) { cout << "jestem operator przypisania" << endl; wiersze = wzor.wiersze; kolumny = wzor.kolumny; int rozmiar = wiersze * kolumny; if( tab ) delete[] tab; tab = new int[ rozmiar ]; for( int i = 0; i < rozmiar; i++ ) { tab[ i ] = wzor.tab[ i ]; } return * this; }
void matrix::setOffset( int offw, int offk ) { if( offw > 0 ) offsetw = offw; else if( offw < 0 ) offsetw = wiersze + offw; else offsetw = 0; if( offk > 0 ) offsetk = offk; else if( offk < 0 ) offsetk = kolumny + offk; else offsetk = 0; }
ostream & operator <<( ostream & s, matrix & m ) { for( int w = 0; w < m.wiersze; w++ ) { for( int k = 0; k < m.kolumny; k++ ) { s << m( w, k ) << " "; } s << endl; } return s; }
int main() { matrix m1( 4, 4 ); int liczba = 10; for( int w = 0; w < m1.row(); w++ ) { for( int k = 0; k < m1.column(); k++ ) { m1( w, k ) = liczba++; } } cout << m1 << endl; m1.setOffset( 1, 1 ); cout << m1 << endl; m1.setOffset( - 1, - 1 ); cout << m1 << endl; m1.setOffset( 0, 0 ); m1( 1, 1 ) = 66; cout << m1( 1, 1 ) << endl; m1.setOffset( 1, 1 ); cout << m1( 0, 0 ) << endl; }
PS. Reasumując. Jeśli masz duże obiekty to trzymaj w tablicy obiektów wskaźniki do nich. stwórz sobie drugą tablice wskaźników i zwyczajnie przekopiuj same wskaźniki. zgodnie z ideą transformacji. Ja zaś zaproponowałem sposób, który sprawia że procedura transformacji jest szybka(tylko ustawienie zmiennych). I możesz z nią szaleć do woli. Ale kosztem nakładu przy dostępie do elementu. //edit kopiowanie wskaźników jest tak samo szybkie jak kopiownaie intów więc robiąc transformację na int zadziała na wskaźnikach. Poniżej kod gotowy do kompilacji i sprawdzenia #include <iostream> using namespace std;
int main() { int matrix[ 5 ][ 5 ]; int matrixT[ 5 ][ 5 ]; int liczba = 10; for( int w = 0; w < 5; w++ ) { for( int k = 0; k < 5; k++ ) { matrix[ w ][ k ] = liczba; matrixT[ w ][ k ] = liczba; liczba++; } } int offw = 1, offk = 1; int offsetw, offsetk; if( offw > 0 ) offsetw = offw; else if( offw < 0 ) offsetw = 5 + offw; else offsetw = 0; if( offk > 0 ) offsetk = offk; else if( offk < 0 ) offsetk = 5 + offk; else offsetk = 0; for( int w = 0; w < 5; w++ ) { for( int k = 0; k < 5; k++ ) { int index_w = w + offsetw; int index_k = k + offsetk; if( index_w >= 5 ) index_w -= 5; if( index_k >= 5 ) index_k -= 5; matrixT[ w ][ k ] = matrix[ index_w ][ index_k ]; } } for( int w = 0; w < 5; w++ ) { for( int k = 0; k < 5; k++ ) { cout << matrixT[ w ][ k ] << " "; } cout << endl; } } |
|
Merulo Temat założony przez niniejszego użytkownika |
» 2016-09-07 22:11:05 Ok, dzięki za kod. Popatrzę sobie.
Jednak problem jest rozwiązany, zrobiłem sobie tablicę która przechowuje informacje o wskaźnikach -> nie muszę przepisywać wartości, więc nie tracę danych. Bardzo wygodne rozwiązanie.
W każdym razie kod który wkleiłeś wygląda sensownie, sprawdzę. |
|
mateczek |
» 2016-09-08 00:41:27 Najlepsze rozwiązanie. kopiowanie tablicy wskaźników to nie jest jakiś problem. A z wszelkimi rotacjami i transformacjami macierzy jest taki problem, że ciężko to zrobić bez dodatkowej tablicy. Z prostego powodu, że przenosząc element zawsze nadpisujesz któryś inny. Z dodatkową tablicą problem prawie zawsze jest łatwiejszy do ogarnięcia.
Kod wkleiłem tylko po to byś sobie skompilował i zobaczył czy o taki efekt ci chodziło:) Analiza czyjegoś kodu zawsze jest kłopotliwa!!! (dla mnie to nie był wielki problem dopisać jedną funkcję do klasy którą już miałem :P )
|
|
« 1 » |