Tutorial 1.1 - ResizableArray

In acest tutorial, ne propunem sa construim o structura de tip Array capabil sa se redimensioneze automat atunci cand se umple.

Obiective

Ne dorim:

  • să construim struct ResizableArray, cu un membru astfel încât să poată reține un vector de elemente de tip int, cu o dimensiune initiala specificata printr-un define
  • să adaugam lui struct ResizableArray o metodă de adăugare a unui element nou. Dacă vectorul intern este deja plin, se va aloca un nou vector de dimensiune dublă, se va copia conținutul original și se va adăuga apoi noul element ca în mod obișnuit
  • să adaugam si alte functionalitati lui struct ResizableArray, precum sortarea elementelor
  • să testam struct ResizableArray printr-un cod simplu care arată cum se adaugă elemente și cum se redimensionează structura de date
  • să verificam cu Valgrind că nu sunt memory leaks.

Dezvoltare

Varianta de baza a lui struct ResizableArray

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__

Adaugarea de elemente si redimensionare

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
}

Adaugarea de alte elemente (e.g. sortarea)

// 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';
}

Testare si Evaluare

Program de test

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

Verificare cu Valgrind

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)
sd-ca/2016/articole/tutorial-01-1.txt · Last modified: 2017/02/04 22:46 by alexandru.olteanu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0