Jump to content

SUBIECTE NOI
« 1 / 5 »
RSS
Presbiopia - la 43 ani ?

Termen transcriere autovehicul

Cazare Timisoara pe 4-5 zile

Primele zile ale internetului per...
 Ditra 25

Casti USB-C ptr A-54

Aplicatie medicala / asistent med...

De ce vor atația politicieni...
 ERR_ADDRESS_UNREACHABLE

Legea 18/1968 Se mai aplica?

Digi conectare 2 routere prin fir

Succesiune notar versus instanta ...
 Montaj aer conditionat in balcon ...

Cont curent mulți valuta far...

Sugestii plan casa

Experiente cu firme care cumpara ...
 

Generatori

- - - - -
  • Please log in to reply
No replies to this topic

#1
dani.user

dani.user

    Guru Member

  • Grup: Senior Members
  • Posts: 30,233
  • Înscris: 24.02.2007
Sa propun azi o abordare ce ajuta la rezolvarea multor feluri de probleme: generators.

Cum putem itera un vector?

Daca avem un vector de intregi, una din cele mai intalnite modalitati de a itera prin el (pentru a afisa, de exemplu, valorile pe ecran) arata cam asa:

int valori[] = { 1, 2, 3, 4, 5 };
for (int i = 0; i < 5; ++i)
{
   int valoare = valori[i];
   std::cout << valoare << " ";
}


E insa singura modalitate? Nu

Cei ce au inteles pointerii se vor gandi probabil la o solutie de genul asta:

int valori[] = { 1, 2, 3, 4, 5 };

int* pointer_valoare_curenta = valori;
int* sfarsit_valori = valori + 5; //pointer spre primul element de dupa sfarsitul vectorului

while (pointer_valoare_curenta != sfarsit_valori)
{
   int valoare = *pointer_valoare_curenta;
   ++pointer_valoare_curenta; //avanseaza la urmatoarea valoare
   std::cout << valoare << " ";
}


Aceasta abordare ajuta mult deoarece:
  • Putem foarte usor sa iteram doar printr-o parte a vectorului, schimband doar pointerii initiali.
  • Putem adapta usor solutia pentru alte structuri de date (gen liste inlantuite)
  • Putem generaliza solutia in mod transparent pentru orice structura de date

Abordarea este atat de populara incat biblioteca standard a C++ ofera o gramada de algoritmi care folosesc aceasta abordare de a parcurge o structura de date. De exemplu, suma tuturor elementelor din vector se poate calcula foarte usor asa:

int valori[] = { 1, 2, 3, 4, 5 };
int suma = std::accumulate(valori, valori + 5, 0);
std::cout << "Suma(valori) = " << suma;


Vrem doar suma a doua elemente incepand cu al doilea? Nici o problema:

int valori[] = { 1, 2, 3, 4, 5 };
int suma = std::accumulate(valori + 1, valori + 3, 0);
std::cout << "Suma(valori) = " << suma;


Ce-i un iterator?

Ce-i un iterator in C++? Un obiect care se comparta ca un pointer de mai sus. Ne ofera valoarea curenta, stie avansa la urmatoarea (sau precedenta), suporta comparatie cu alt iterator.

Asadar, daca schimbam vectorul clasic de mai sus cu unul din STL, putem repeta operatiile de mai sus intr-un mod aproape identic, doarece vectorul ne ofera iteratori.

std::vector<int> valori = { 1, 2, 3, 4, 5 };
std::vector<int>::iterator iterator = valori.begin();
std::vector<int>::iterator iterator_sfarsit = valori.end();

while (iterator != iterator_sfarsit)
{
   int valoare = *iterator;
   ++iterator;
   std::cout << valoare << " ";
}



std::vector<int> valori = { 1, 2, 3, 4, 5 };
int suma = std::accumulate(valori.begin() + 1, valori.begin() + 3, 0);
std::cout << "Suma(valori) = " << suma;


std::vector<int> valori = { 1, 2, 3, 4, 5 };
int suma = std::accumulate(valori.begin(), valori.end(), 0);
std::cout << "Suma(valori) = " << suma;


Ziceam mai sus ca solutia se poate generaliza. Daca am folosi o lista inlantuita s-ar schimba ceva? Aproape nimic.

std::list<int> valori = { 1, 2, 3, 4, 5 };
std::list<int>::iterator iterator = valori.begin();
std::list<int>::iterator iterator_sfarsit = valori.end();

while (iterator != iterator_sfarsit)
{
   int valoare = *iterator;
   ++iterator;
   std::cout << valoare << " ";
}



std::list<int> valori = { 1, 2, 3, 4, 5 };
int suma = std::accumulate(valori.begin() + 1, valori.begin() + 3, 0);
std::cout << "Suma(valori) = " << suma;


std::list<int> valori = { 1, 2, 3, 4, 5 };
int suma = std::accumulate(valori.begin(), valori.end(), 0);
std::cout << "Suma(valori) = " << suma;


Ce-i un generator?

Daca am avea un vector cu toate elementele de la 1 la 1000, am putea foarte usor folosi iteratori pentru a-l parcurge. Dar a numara de la 1 la 1000 e ceva trivial, de ce ar trebui sa umplu memoria cu toate valorile pentru asa ceva?

Aici intervine un generator: un iterator mai special ce iti genereaza pe loc valoarea curenta, n-o citeste pur si simplu dintr-o colectie.

La ce ar putea ajuta un astfel de generator? De exemplu la obtinerea sirului lui Fibonacci. Daca am dori sa iteram pe rand valorile sirului, beneficiam de avantaje din ambele directii:

  • Parcurgem generatorul ca si cum am fi avut un vector cu toate valorile deja calculate
  • Calculam insa valoarea pe loc, cand e nevoie; nu calculez in avans primele 100 valori ca apoi sa n-am nevoie decat de 10

class FibonacciGenerator
{
public:
   //instiintam algoritmii ca e un iterator ce stie merge doar inainte, cate un pas odata
   typedef std::input_iterator_tag iterator_category;
   typedef uint64_t value_type;
   typedef uint64_t* pointer;
   typedef uint64_t* reference;

   FibonacciGenerator()
   {
	  currentIndex = 0;
	  //primele doua valori sunt fixate
	  lastValues[0] = 0;
	  lastValues[1] = 1;
   }

   static FibonacciGenerator FibonacciGenerator::end()
   {
	  //returnam un iterator de dupa finalul sirului; 
	  //sirul e infinit, insa folosind uint64_t incap doar vreo 93 elemente
	  FibonacciGenerator result;
	  result.currentIndex = 100;
	  return result;
   }

   uint64_t operator*() const
   {
	  //daca suntem la primul sau al doilea element, returnam valorile fixate
	  //atfel returnam suma ultimelor doua valori
	  if (currentIndex == 0)
	  {
		 return lastValues[0];
	  }
	  if (currentIndex == 1)
	  {
		 return lastValues[1];
	  }
	  return lastValues[0] + lastValues[1];
   }

   bool operator==(const FibonacciGenerator& other) const
   {
	  return currentIndex == other.currentIndex;
   }

   bool operator!=(const FibonacciGenerator& other) const
   {
	  return ! (*this == other);
   }

   FibonacciGenerator& operator++()
   {
	  currentIndex += 1;
	  if (currentIndex > 2)
	  {
		 uint64_t currentValue = **this;
		 lastValues[0] = lastValues[1];
		 lastValues[1] = currentValue;
	  }

	  return *this;
   }

   FibonacciGenerator operator++(int)
   {
	  FibonacciGenerator temp = *this;
	  ++*this;
	  return temp;
   }

private:
   //tinem minte precedentele doua valori
   uint64_t lastValues[2];
   //la al catelea element din sir am ajuns
   uint64_t currentIndex;
};


Vrem sa afisam primele 50 elemente? Nimic mai simplu

FibonacciGenerator fibonacci;

for (size_t i = 0; i < 50; i++)
{
   std::cout << "Fibonacci(" << i + 1 << ") = " << *fibonacci++ << "\n";
}


Quote

Fibonacci(1) = 0
Fibonacci(2) = 1
Fibonacci(3) = 1
Fibonacci(4) = 2
Fibonacci(5) = 3
Fibonacci(6) = 5
Fibonacci(7) = 8
Fibonacci(8) = 13
Fibonacci(9) = 21
Fibonacci(10) = 34
Fibonacci(11) = 55
Fibonacci(12) = 89
Fibonacci(13) = 144
Fibonacci(14) = 233
Fibonacci(15) = 377
Fibonacci(16) = 610
Fibonacci(17) = 987
Fibonacci(18) = 1597
Fibonacci(19) = 2584
Fibonacci(20) = 4181
Fibonacci(21) = 6765
Fibonacci(22) = 10946
Fibonacci(23) = 17711
Fibonacci(24) = 28657
Fibonacci(25) = 46368
Fibonacci(26) = 75025
Fibonacci(27) = 121393
Fibonacci(28) = 196418
Fibonacci(29) = 317811
Fibonacci(30) = 514229
Fibonacci(31) = 832040
Fibonacci(32) = 1346269
Fibonacci(33) = 2178309
Fibonacci(34) = 3524578
Fibonacci(35) = 5702887
Fibonacci(36) = 9227465
Fibonacci(37) = 14930352
Fibonacci(38) = 24157817
Fibonacci(39) = 39088169
Fibonacci(40) = 63245986
Fibonacci(41) = 102334155
Fibonacci(42) = 165580141
Fibonacci(43) = 267914296
Fibonacci(44) = 433494437
Fibonacci(45) = 701408733
Fibonacci(46) = 1134903170
Fibonacci(47) = 1836311903
Fibonacci(48) = 2971215073
Fibonacci(49) = 4807526976
Fibonacci(50) = 7778742049

Edited by dani.user, 26 October 2016 - 11:18.


Anunturi

Chirurgia endoscopică a hipofizei Chirurgia endoscopică a hipofizei

"Standardul de aur" în chirurgia hipofizară îl reprezintă endoscopia transnazală transsfenoidală.

Echipa NeuroHope este antrenată în unul din cele mai mari centre de chirurgie a hipofizei din Europa, Spitalul Foch din Paris, centrul în care a fost introdus pentru prima dată endoscopul în chirurgia transnazală a hipofizei, de către neurochirurgul francez Guiot. Pe lângă tumorile cu origine hipofizară, prin tehnicile endoscopice transnazale pot fi abordate numeroase alte patologii neurochirurgicale.

www.neurohope.ro

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

Forumul Softpedia foloseste "cookies" pentru a imbunatati experienta utilizatorilor Accept
Pentru detalii si optiuni legate de cookies si datele personale, consultati Politica de utilizare cookies si Politica de confidentialitate