//Resenje kolege Slavka Moconje.

#include <iostream>
using namespace std;

class Stek{
	public:
	class Element{
		public:
			int Vrednost()const{
			return _Vrednost;
			}

			Element *Sledeci()const{
			return _Sledeci;
			}
		private:
			Element(int V, Element *S=0): _Vrednost(V), _Sledeci(S){}
			int _Vrednost;
			Element *_Sledeci;
			friend class Stek;
		};

	// Konstruktor bez argumenata
	Stek():_Pocetak(0), _BrElemenata(0){}

	// Konstruktor kopije
	Stek(const Stek &S){
	init(S);
	}

	// Operator dodele
	Stek operator =(const Stek &S){
		if ((*this)._Pocetak != S._Pocetak){
		deinit();
		init(S);
		}
	return *this;
	}

	// Destruktor
	~Stek(){
	deinit();
	}

	// Stavlja element na vrh steka
	void Push(const int n){
	_Pocetak = new Element(n, _Pocetak);
	_BrElemenata++;
	}

	// Skida element sa vrha steka i vraca njegovu vrednost
	int Pop(){
	if (Empty())
		return 0;
	int n=_Pocetak->Vrednost();
	Element *p=_Pocetak;
	_Pocetak=_Pocetak->Sledeci();
	delete p;
	_BrElemenata--;
	return n;
	}

	// Vraca vrednost koja se nalazi na vrhu steka
	int Top()const{
	return _Pocetak->Vrednost();
	}

	// Proverava da li je stek prazan
	bool Empty()const{
	return !_Pocetak;
	}

	// Vraca broj elemenata steka
	int Count()const{
	return _BrElemenata;
	}

	// Funkcija koja obezbedjuje upis
	istream &Upis(istream &istr){
	int BrEl;
	cout<<"Unesite br. novih elemenata steka: ";
	istr>>BrEl;
	for (int i=0; i<BrEl; i++){
		int El;
		cout<<"Unesite element steka: ";
		istr>>El;
		Push(El);
		}
	return istr;
	}

	// Funkcija koja obezbedjuje ispis
	ostream &Ispis(ostream &ostr)const{
	for (Element *p=_Pocetak; p; p=p->Sledeci())
		ostr << p->Vrednost()<<" ";
	return ostr;
	}

	// Skida dva elementa sa vrha steka, 
	// sabira njihove vrednosti i zbir
	// vraca na vrh steka
	Stek operator +(){
	if (_BrElemenata>=2)
		Push(Pop()+Pop());
	return *this;
	}

	// Sabira vrednost vrha steka sa celim brojem
	Stek operator +(const int &I){
	if (_BrElemenata)
		Push(Pop()+I);
	return *this;
	}

	// Skida dva elementa sa vrha steka, 
	// mnozi njihove vrednosti i proizvod
	// vraca na vrh steka 
	Stek operator *(){
	if (_BrElemenata>=2)
		Push(Pop()*Pop());
	return *this;
	}

	// Mnozi vrednost vrha steka sa celim brojem
	Stek operator *(const int &I){
	if (_BrElemenata)
		Push(Pop()*I);
	return *this;
	}

	// Menja znak elementa na vrhu steka
	Stek operator -(){
	if (_BrElemenata)
		Push(-Pop());
	return *this;
	}

	private:
	void init(const Stek &S){
	_BrElemenata=S.Count();
	Element *stari=S._Pocetak;
	Element *novi=0;
	while (stari){
		Element *temp=new Element(stari->Vrednost());
		if (!novi)
			_Pocetak=novi=temp;
		else{
			novi->_Sledeci=temp;
			novi=novi->_Sledeci;
			}
		stari=stari->Sledeci();
		}
	}

	void deinit(){
		while (!Empty()){
		Element *p=_Pocetak;
		_Pocetak=_Pocetak->Sledeci();
		delete p;
		}
	}

	Element *_Pocetak;
	int _BrElemenata;
};

istream& operator >> (istream &istr, Stek &S){
return S.Upis(istr);
}

ostream& operator << (ostream &ostr, Stek &S){
return S.Ispis(ostr);
}

//Funkcija main ilustruje koriscenje klase stek
main()
{
Stek S1;

S1.Push(2);
S1.Push(3);
S1.Push(5);
S1.Push(7);
S1.Push(11);

cout << S1<<endl;

-S1;
cout << S1<<endl;

+S1;
cout << S1<<endl;

*S1;
cout << S1<<endl;

S1+10;
cout << S1<<endl;

S1*10;
cout << S1<<endl;

cin >> S1;
cout << S1 <<endl;
return 0;
}
   
/*
Ilustracija rada programa:
11 7 5 3 2
-11 7 5 3 2
-4 5 3 2
-20 3 2
-10 3 2
-100 3 2
Unesite br. novih elemenata steka: 5
Unesite element steka: 1
Unesite element steka: 2
Unesite element steka: 3
Unesite element steka: 4
Unesite element steka: 5
5 4 3 2 1 -100 3 2
*/
