Wielowymiarowe wektory

0

Witam,
ostatnio natrafiłem gdzieś w internecie na artykuł o wektorach w C++ i mówiąc szczerzę gościu tam się wypowiadający mnie przekonał.
Mam jednak kilka pytań co do tego;
-Czy to rzeczywiście tak jest z tymi wektorami, że to niby są lepsze niż tablice i zużywają mniej pamięci?
-Jak tworzy się vektory wielowymiarowe (chodzi mi tutaj o taki 4-wymiarowy)
Podrawiam.
Wesołych świąt i szczęśliwego Nowego Roku :D

1

Czy to rzeczywiście tak jest z tymi wektorami, że to niby są lepsze niż tablice i zużywają mniej pamięci?

Nie, zajmują tyle samo lub więcej miejsca. Wektor sam realokuje pamięć gdy jej potrzebuje, ale alokuje jej więcej niż potrzebujesz po to żeby przy dodawaniu elementów nie musiał realokować co chwilę. Główną zaletą jest to, że nie musisz się w to ręcznie bawić, a działa on praktycznie tak samo jak ręcznie alokowana tablica. Osobiście używaj vectorów, list, map, ... gdzie się tylko da, ale używaj tylko tej struktury której rzeczywiście potrzebujesz.

Jak tworzy się vektory wielowymiarowe (chodzi mi tutaj o taki 4-wymiarowy)

vector< vector<typ> vector_dwuwymiarowy;
vector< vector< vector<typ> > > vector_trojwymiarowy; (zwroc uwage na spacje miedzy > >, nie wolno jej pominąć)

0

Nie mam teraz przy sobie kompilatora jednak spytam dla pewności:
Wektor cztero(czwór?)wymiarowy robi się tak:
vector< vector< vector< vector<typ> > > > nazwa_vectora;
?
No i jak przypisać wartości do tego np. czwartego wymiaru?
nazwa_vectora[0][0][0][4] = liczba?

0

Jesli nie nadasz mu wczesniej wielkosci to wtedy musisz np. do tego ostatniego wymiaru wrzucic caly vector push.backiem tab[0][0][0].push_back(tab2) gdzie tab 2 bedzie vectorem 1 wymiarowym. Dokladnie skladni teraz nie pamietam, bo z pamieci, ale jakos tak to wygladalo.

0
Krycho napisał(a)

Jesli nie nadasz mu wczesniej wielkosci to wtedy musisz np. do tego ostatniego wymiaru wrzucic caly vector push.backiem tab[0][0][0].push_back(tab2) gdzie tab 2 bedzie vectorem 1 wymiarowym. Dokladnie skladni teraz nie pamietam, bo z pamieci, ale jakos tak to wygladalo.

Nie do końca rozumiem.
Chcę dodać po prostu w odpowiednie miejsce liczbę (int) i zastanawiam się czy taki sposób jest poprawny:

vector< vector< vector< vector<int> > >  > nazwa_vectora;
nazwa_vectora[0][0][0][4] = 1;

EDIT:
No i rozumiem że vektory nie będą powiększać się automatycznie jeśli będę chciał dodać dane poza zakresem. Co wtedy zrobić?

0

Jest tak ze jesli tworzysz

vector <int> nazwa

to wtedy taki vector jakby nie ma wielkosci i kazdy element trzeba mu dodawac poprzez nazwa.push_back(int). Natomiast jesli stworzysz vector <int> nazwa(5)

 to masz 5 elementowy vector i mozesz normlanie mu przypisac nazwa[0]=1
Przy wiekszych vectorach jest to samo. Tylko w nawiasie wielkosc sie podawalo jakos(przy 2 wymiarach) 
```cpp
vector< vector<int> >nazwa(4, vector <int>(4))

i masz vector 4 na 4 gdzie mozesz sie odwolywac poprzesz nazwa[0][0]. Dalej analogicznie.

0
Krycho napisał(a)

Jest tak ze jesli tworzysz

vector <int> nazwa

to wtedy taki vector jakby nie ma wielkosci i kazdy element trzeba mu dodawac poprzez nazwa.push_back(int). Natomiast jesli stworzysz vector <int> nazwa(5)

 to masz 5 elementowy vector i mozesz normlanie mu przypisac nazwa[0]=1
> Przy wiekszych vectorach jest to samo. Tylko w nawiasie wielkosc sie podawalo jakos(przy 2 wymiarach) 
```cpp
vector< vector<int> >nazwa(4, vector <int>(4))

i masz vector 4 na 4 gdzie mozesz sie odwolywac poprzesz nazwa[0][0]. Dalej analogicznie.

Nadal nie kumam wszystkiego:

kazdy element trzeba mu dodawac poprzez nazwa.push_back(int).

Rozumiem że "int" to jakaś liczba i nie podaję tutaj typu zmiennej.
A jeśli chciałbym dodać element z drugiego wymiaru? Czy jak to działa?
No bo teraz opisałeś chyba jak to się robi przy wektorach jednowymiarowych. Ja natomiast chcę używać 4-wymiarowych. Jak więc mam dodawać elementy do takiego wektora?

1
#include <iostream>
#include <vector>

using namespace std;
int main()
{
    vector< vector< vector< vector<int> > > > tab;
    vector< vector< vector<int> > >tab4;
    vector< vector<int> >tab2;
    vector<int> tab3;
    tab3.push_back(5);
    tab3.push_back(2);
    tab2.push_back(tab3);
    tab4.push_back(tab2);
    tab.push_back(tab4);
    cout << tab[0][0][0][0]; //5
    cout << tab[0][0][0][1]; //2
    return 0;
}

Masz wektor 4 wymiarowy. Jesli nie masz sprecyzowanej wielkosci musisz mu robic cos takiego. Najpierw najbardziej podstawowy wektor 1 wymiarowy. Dodajesz elementy i wrzucasz do 2 wymiarowego caly wektor. Potem do 3 i na koncu do 4. To jest tak jakby kazdy element tego 4 wymiarowego wektora byl wektorem 3 wymiarowym. Nie potrafie tego dobrze wyjasnic po prostu tak jest ;).

2
 vector< vector<int> >      JestemWektorem(4, vector<int>(4)); 

Dwuwymiarowy wektor 4x4
Analogicznie robi się czterowymiarowy:


//vector< int > //1D
//vector< vector< int > >  //2D  
//vector< vector< vector< int > > >  //3D
//vector< vector< vector< vector< int > > > > //4D




vector< vector< vector< vector< int > > > >  JestemWektorem(4, vector< vector< vector <int> > >(4,  vector< vector<  int > >(4, vector< int >(4, -1) ) ) );
//Czterowymiarowy wektor intów, o startowym rozmiarze 4x4x4x4, wypełniony domyślnie w całości wartością -1;

JestemWektorem[0][0][0][2]=5;
JestemWektorem[3][3][3][3]=-2;
JestemWektorem[0][1][2][3]=0;

cout << JestemWektorem[0][0][0][2] << endl << JestemWektorem[3][3][3][3] << endl << JestemWektorem[0][1][2][3] << endl << JestemWektorem[3][2][1][0];
//Wypisujemy co wpisaliśmy i jedno inne, żeby zobaczyć, że się dobrze wypełniło na starcie.

 

Potem możesz go sobie poszerzać za pomocą resize() albo dodawać elementy na wierzch przez push_back().
Oczywiście3 wygodniej byłoby sobie zrobić jakieś typedefy do tego, na przykład tak jak tutaj - http://www.daniweb.com/software-development/cpp/threads/137814

 
typedef  vector<int>       vector1D;
typedef  vector<vector1D>  vector2D;
typedef  vector<vector2D>  vector3D;
typedef  vector<vector3D>  vector4D;


vector4D JestemWektorem(4, vector3D(4, vector2D(4, vector1D(4,-1) )  ) );

JestemWektorem[0][0][0][2]=5;
JestemWektorem[3][3][3][3]=-2;
JestemWektorem[0][1][2][3]=0;

cout << JestemWektorem[0][0][0][2] << endl << JestemWektorem[3][3][3][3] << endl << JestemWektorem[0][1][2][3] << endl << JestemWektorem[3][2][1][0];

Na przykład tak.

1

dodam jeszcze, że w C++11 nie trzeba kombinować z osobnym wypełnianiem push_backami podwektorów i podwektorów tych podwektorów, tylko można zapodać takiego kombosa:

  vector<vector<vector<vector<int>>>> tab = 
  {{{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}}},
   {{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}}},
   {{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}}},
   {{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}}}};
 
  cout << tab[1][1][1][1] << endl;

a nawet

const vector<vector<vector<vector<int>>>> tab = // itd.

— spróbujcie to zrobić z constem w poprzednim standardzie…

0
Azarien napisał(a)

dodam jeszcze, że w C++11 nie trzeba kombinować z osobnym wypełnianiem push_backami podwektorów i podwektorów tych podwektorów, tylko można zapodać takiego kombosa:

  vector<vector<vector<vector<int>>>> tab = 
  {{{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}}},
   {{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}}},
   {{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}}},
   {{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}},{{1,2,3},{1,2,3}}}};
 
  cout << tab[1][1][1][1] << endl;

a nawet

const vector<vector<vector<vector<int>>>> tab = // itd.

— spróbujcie to zrobić z constem w poprzednim standardzie…

OK. Wszystko jasne :D
Tak z ciekawości spytam: jak sprawdzić jakie mam C++?
Mówiąc szczerze nigdy nie wiedzialem że istnieją rózne wersje tego języka.

1

W zasadzie standard jest jeden. ISO/IEC 14882:2011, zwany C++11, przyjęty 12 sierpnia br. Oczywiście nie wszystkie kompilatory wspierają go w 100%, dlatego przez jakiś czas będzie sie mówić o tym C++11 i poprzednim C++03 i o tym jak to różne rzeczy działają w nich inaczej. W GCC trzeba dodać -std=c++0x do komendy kompilatora, żeby go używać, w MSVC (cl) chyba nie trzeba niczego dodawać.

0
Jadeszek napisał(a)

[...]

Potem możesz go sobie poszerzać za pomocą resize() albo dodawać elementy na wierzch przez push_back().
Oczywiście3 wygodniej byłoby sobie zrobić jakieś typedefy do tego, na przykład tak jak tutaj - http://www.daniweb.com/software-development/cpp/threads/137814

A czy to rozszerzanie jest konieczne?
Nie lubię mieć braków w wiedzy więc zagłębiłem się w te arcyciekawy artykuł (:P):
http://sadi.ovh.org/arty/cppwektory.php
W którym autor niezbicie twierdzi, że wektory same sobie znajdują pamięć dla naszych zmiennych i nie trzeba troszczyć się o wstawianie "push_back()" i tym podobnych.
Jest to w części: "Wektory, a dynamiczne tablice"

Zwróć uwagę na to, że deklarujemy tylko 3 elementy, a dalej chcemy operować na 10. Jest to jawne wykroczenie poza zakres, połączone z niszczeniem danych z pamięci, która nie należy do naszego programu. A raczej tak by było, gdybyśmy użyli zwykłej tablicy. Wektor jednak jest na tyle sprytny, że zwiększa swoje rozmiary, gdy chcemy coś zrobić z polem, które nie istnieje. Innymi słowy wektor zawsze ma dokładnie tyle pól ile trzeba, ale nie mniej niż zadeklarowaliśmy. Dlatego stosując wektor w programie, w którym najpierw pobieramy od użytkownika rozmiar tablicy, a potem jej elementy, praktycznie nie obchodzą nas kwestie związane z pamięcią!

A więc jak to w końcu jest? ^^

1

Lolwut. Zmień w tamtym kodzie [i] na .at(i) i dostaniesz piękny wyjątek. Przy [i] runtime się również wysypuje. std::vector nic sam nie zrobi, to jakieś brednie.

0

OK. Tym razem to już mam nadzieję ostatnia wątpliwość:
Jak użyć "push_back()" do wielowymiarowego wektora,jeśli przykładowo chciałbym dodać element z wymiaru trzeciego?
Ja nie wiem jakim cudem tego nie ma w internecie. Toż to podstawa.
EDIT:
Co prawda kolega dał tutaj kod:

Krycho napisał(a)
#include <iostream>
#include <vector>

using namespace std;
int main()
{
    vector< vector< vector< vector<int> > > > tab;
    vector< vector< vector<int> > >tab4;
    vector< vector<int> >tab2;
    vector<int> tab3;
    tab3.push_back(5);
    tab3.push_back(2);
    tab2.push_back(tab3);
    tab4.push_back(tab2);
    tab.push_back(tab4);
    cout << tab[0][0][0][0]; //5
    cout << tab[0][0][0][1]; //2
    return 0;
}

Masz wektor 4 wymiarowy. Jesli nie masz sprecyzowanej wielkosci musisz mu robic cos takiego. Najpierw najbardziej podstawowy wektor 1 wymiarowy. Dodajesz elementy i wrzucasz do 2 wymiarowego caly wektor. Potem do 3 i na koncu do 4. To jest tak jakby kazdy element tego 4 wymiarowego wektora byl wektorem 3 wymiarowym. Nie potrafie tego dobrze wyjasnic po prostu tak jest ;).

natomiast tu jest straszny "misz-masz". Nic nie rozumiem.
I nie da się tego rozwiązać bez potrzeby tworzenia innych wektorów?</del>
Działa :D

0

Wprowadziłem ten kod w życie:

vector< vector< vector< vector<int> > > > Vpush_back(int dana,  vector< vector< vector< vector<int> > > >vector4){
    vector< vector< vector<int> > >vector3;
    vector< vector<int> >vector2;
    vector<int> vector1;

    vector1.push_back(dana);
    vector2.push_back(vector1);
    vector3.push_back(vector2);
    vector4.push_back(vector3);

    return vector4;
}

Tknął mnie tylko jeden mały szczegół :/
Za każdym razem nowa liczba będzie dodawana na początek (czyli zawsze zmieniane będzie to: vector[0][0][0][0])
Dlaczego? Bo za każdym razem tworzymy od nowa vector1 :/
Czy ktoś zna jakieś rozwiązanie co zrobić aby dodać następny element do wektora a nie nadmienić pierwszy?
PS: Nie ma tutaj opcji typu: usuń post? Poprzedni wysłał się 2 razy.

1 użytkowników online, w tym zalogowanych: 0, gości: 1