In acest tutorial, ne propunem sa construim o structura de tip Array capabil sa se redimensioneze automat atunci cand se umple.
Ne dorim:
Vom considera ca varianta de baza o structura care contine un array de MAX_SIZE elemente, unde MAX_SIZE este initializat printr-un define.
#ifndef __RESIZABLE_ARRAY__ #define __RESIZABLE_ARRAY__ #define MAX_SIZE 100 // o dimensiune maxima prestabilita struct ResizableArray { int array[ MAX_SIZE ]; }; #endif // __RESIZABLE_ARRAY__
Pentru a putea adauga elemente si a sti cand vectorul este plin avem nevoie de capacitatea acestuia si de dimensiunea sa la un moment dat. De asemenea, ca sa il putem realoca, array-ul nu va fi initializat static!
struct ResizableArray { int *array; int capacity; int size; // Metoda de initializare void init(int capacity) { this->capacity = capacity; this->size = 0; this->array = new int[ capacity ]; } }
Metoda care adauga un element in vector ar trebui initial sa verifice daca mai este loc. In caz afirmativ, elementul se va pune pe urmatoarea pozitie libera in vector. Altfel, capacitatea vectorului se va dubla si se va actualiza la noua valoare. De asemenea, deoarece in C++ nu folosim “realloc”, vom folosi un pointer auxiliar pentru noua dimensiune pe care il vom completa cu valorile deja existente.
void push_back(int value) { // Verific daca vectorul intern este plin if (size == capacity) { // Voi face o realocare. La final copiez elementele in noul vectorl // Aloc un nou vector de dimensiune dubla. int *tmpArray = new int[ 2*capacity ]; // Copiez elementele in noul vector for ( int i = 0; i < size; ++i ) { tmpArray[ i ] = array[ i ]; } // Eliberez memoria ocupata de vechiul vector. delete[] array; // Salvez vectorul nou format, care are capacitate dubla. array = tmpArray; capacity = 2 * capacity; } // Adaug elementul la finalul vectorului // Pozitia noului element este size; array[ size ] = value; size++; // urmatorul element adaugat va fi adaugat la o urmatoarea pozitie }
// Metoda care sorteaza crescator elementele vectorului. void sort() { for ( int i = 0; i < size; ++i ) { for ( int j = i + 1; j < size; ++j ) { if (array[ i ] > array[ j ]) { int tmp = array[i]; array[ i ] = array[ j ]; array[ j ] = tmp; // sau std::swap(array[i], array[j]); // sau array[i] ^= array[j], array[j] ^= array[i], array[i] ^= array[j]; } } } } // Metoda care afiseaza elementele vectorului. void print() { std::cout << "Continut: "; for ( int i = 0; i < size; ++i ) { std::cout << array[i] << ' '; } std::cout << '\n'; }
In continuare vom face un program care prima data citeste n numere intr-un ResizableArray de dimensiune n, apoi mai citeste inca m numere pe care le introduce in acelasi ResizableArray pentru a demonstra realocarea, iar apoi va afisa elementele inainte si dupa sortarea acestora.
#include <iostream> #include "ResizableArray.h" int main() { // Declararea unui element de tip ResizableArray ResizableArray ra; // Initializarea (alocarea vectorului intern). Presupunem ca are o dimensiune n; int n; std::cout << "n = "; std::cin >> n; ra.init(n); // Citirea si adaugarea a n elemente. for ( int i = 0; i < n; ++i ) { int x; // al i-lea element citit de la tastatura std::cin >> x; ra.push_back(x); // Observatie: Capacitatea vectorului intern nu se modifica. std::cout << "Dimensiune: " << ra.size << " Capacitate " << ra.capacity << '\n'; } // Afisare continut vector ra.print(); // Vom adauga in continuare inca m elemente; int m; std::cout << "m = "; std::cin >> m; for ( int i = 0; i < m; ++i ) { int x; // al i-lea element citit de la tastatura std::cin >> x; ra.push_back(x); // Observatie: Se poate modifica capacitatea vectorului intern! std::cout << "Dimensiune: " << ra.size << " Capacitate " << ra.capacity << '\n'; } // Afisare continut vector std::cout << "Inainte de sortare\n"; ra.print(); // Vom sorta elementele apoi vom afisa din nou continutul. ra.sort(); std::cout << "Dupa sortare\n"; ra.print(); // Eliberare memorie delete[] ra.array; return 0; }
Exemplu:
n = 5 1 Dimensiune: 1 Capacitate 5 7 Dimensiune: 2 Capacitate 5 13 Dimensiune: 3 Capacitate 5 2 Dimensiune: 4 Capacitate 5 41 Dimensiune: 5 Capacitate 5 Continut: 1 7 13 2 41 m = 6 1 Dimensiune: 6 Capacitate 10 5 Dimensiune: 7 Capacitate 10 2 Dimensiune: 8 Capacitate 10 -2 Dimensiune: 9 Capacitate 10 1 Dimensiune: 10 Capacitate 10 4 Dimensiune: 11 Capacitate 20 Inainte de sortare Continut: 1 7 13 2 41 1 5 2 -2 1 4 Dupa sortare Continut: -2 1 1 1 2 2 4 5 7 13 41
Pentru acelasi test rulat cu
valgrind ./main.out
toata memoria va fi eliberata.
==8090== HEAP SUMMARY: ==8090== in use at exit: 0 bytes in 0 blocks ==8090== total heap usage: 3 allocs, 3 frees, 140 bytes allocated ==8090== ==8090== All heap blocks were freed -- no leaks are possible ==8090== ==8090== For counts of detected and suppressed errors, rerun with: -v ==8090== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)