#include <iostream>

using namespace std;

class Niz
{
public:
	Niz()
		: _Elementi( 0 ),
		  _Alocirano( 0 ),
		  _Velicina( 0 )
		{}

	~Niz()
		{ delete [] _Elementi; }

	Niz( const Niz& n )
		{ init(n); }

	Niz& operator = ( const Niz& n )
		{ 
		if( this != &n ){
			delete [] _Elementi;			
			init(n); 
			}
		return *this;
		}
		
	int& operator[] ( unsigned i )
		{ 
		if( i >= Velicina() )
			PromeniVelicinu( i + 1 );
		return _Elementi[i]; 
		}
		
	unsigned Velicina() 
		{ return _Velicina; }
	
	// ovo stavljamo samo radi provere
	unsigned Alocirano() 
		{ return _Alocirano; }
		
	void PromeniVelicinu( unsigned v )
		{
		if( v != _Velicina ){
			if( v >= _Alocirano ){
				_Alocirano = v * 1.5;
				if( _Alocirano < 16 )
					_Alocirano = 16;
				/* alternativni algoritam povecavanja niza					
				while( _Alocirano <= v )
					_Alocirano *= 2;
				*/				
				int* noviNiz = new int[_Alocirano];
				for( unsigned i=0; i<_Velicina; i++ )
					noviNiz[i] = _Elementi[i];
				delete [] _Elementi;
				_Elementi = noviNiz;
				}
			else if( v * 1.5 < _Alocirano ){
				_Alocirano = v;
				int* noviNiz = 
					_Alocirano > 0 
						? new int[_Alocirano]
						: 0;
				for( unsigned i=0; i<_Velicina && i<v; i++ )
					noviNiz[i] = _Elementi[i];
				delete [] _Elementi;
				_Elementi = noviNiz;
				}
			_Velicina = v;
			}
		}
		
	void DodajNaKraj( int x )
		{ (*this)[_Velicina] = x; }
		
	void ObrisiSaKraja()
		{ 
		if( _Velicina )
			_Velicina--;
		}
		
	int Poslednji()
		{
		return _Velicina
			? _Elementi[_Velicina-1]
			: 0;
		}	

private:
	void init( const Niz& n )
		{
		_Velicina = n._Velicina;
		_Alocirano = _Velicina;
		_Elementi = new int[_Alocirano];
		for( unsigned i=0; i<_Velicina; i++ )
			_Elementi[i] = n._Elementi[i];
		}

	int* 		_Elementi;
	unsigned	_Velicina;
	unsigned	_Alocirano;
};

main()
{
	cout << "Punjenje i citanje elemenata niza:" << endl;
	Niz a;
	for( unsigned i=0; i<10; i++ )
		a[i] = i;
	
	cout << a.Velicina() << endl;
	for( unsigned i=0; i<a.Velicina(); i++ )
		cout << a[i] << ' ';
	cout << endl;
	
	cout << "Promena velicine niza:" << endl;
	a.PromeniVelicinu( 5 );
	cout << a.Velicina() << endl;
	for( unsigned i=0; i<a.Velicina(); i++ )
		cout << a[i] << ' ';
	cout << endl;
	
	cout << "Konstruktor kopije:" << endl;
	Niz b=a;
	cout << b.Velicina() << endl;
	for( unsigned i=0; i<b.Velicina(); i++ )
		cout << b[i] << ' ';
	cout << endl;

	cout << "Dodavanje na kraj:" << endl;
	for( unsigned i=100; i<150; i++ )
		a.DodajNaKraj( i );
	cout << a.Velicina() << endl;
	
	cout << "Brisanje sa kraja:" << endl;
	for( unsigned i=0; i<20; i++ )
		a.ObrisiSaKraja();
	cout << a.Velicina() << endl;
	cout << a.Poslednji() << endl;
		
	cout << "Pristupanje 'na preskok':" << endl;
	a[1000] = 212121;
	cout << a.Velicina() << endl;
	cout << a[1000] << endl;
	
	cout << "Proveru da li je kopija menjana:" << endl;
	cout << b.Velicina() << endl;
	for( unsigned i=0; i<b.Velicina(); i++ )
		cout << b[i] << ' ';
	cout << endl;
	
	cout << "Operator dodeljivanja:" << endl;
	b = a;
	cout << b.Velicina() << endl;

	cout << "Smanjivanje niza:" << endl;
	cout << a.Velicina() << " : " << a.Alocirano() << endl;
	a.PromeniVelicinu(900);
	cout << a.Velicina() << " : " << a.Alocirano() << endl;
	a.PromeniVelicinu(800);
	cout << a.Velicina() << " : " << a.Alocirano() << endl;
	a.PromeniVelicinu(100);
	cout << a.Velicina() << " : " << a.Alocirano() << endl;
	
	return 0;		
}

