LRU keš

Napisati generičku klasu LRU_kes<K, V> koja implementira LRU (engl. Least Recently Used) keš sa ključevima tipa K i vrednostima tipa V. Klasa treba da podržava sledeće operacije:

Sve operacije treba da budu složenosti ne veće od $O(1)$.

Ulaz

Sa standardnog ulaza prvo se učitava maksimalni kapacitet keša $n$, a zatim, sve do kraja ulaza, i niz upita u formatu:

Izlaz

Na standardni izlaz ispisati rezultate izvršavanja naredbi u k. Ako neka naredba baci izuzetak, ispisati poruku izuzetka na standardni izlaz za greške.

Primer

stdin

2
s 1 1
s 2 2
u 1
s 3 3
u 2
s 4 4
u 1
u 3
u 4

stdout

1
Kljuc nije u kesu
Kljuc nije u kesu
3
4   

Rešenje

main.cpp

#include <iostream>
#include <iterator>
#include <list>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <utility>

namespace matf
{
	/* Klasa za LRU kes */
	template <typename K, typename V>
	class LRU_kes
	{
		typedef typename std::pair<K, V> Par;
		typedef typename std::list<Par>::iterator ListIt;

		public:
			/* Konstruktor sa zadatim kapacitetom kesa */
			LRU_kes(size_t _kapacitet) : kapacitet(_kapacitet) {}

			/* Dodaje par kljuc-vrednost u kes */
			void stavi(const K& kljuc, const V& vrednost)
			{
				// Ako par sa datim kljucem vec postoji, ukloni ga iz liste i mape
				auto it = mapa_stavki.find(kljuc);
				if (it != mapa_stavki.end()) {
					lista_stavki.erase(it->second);
					mapa_stavki.erase(it);
				}

				// Dodaj novi par na pocetak liste i u mapu
				lista_stavki.push_front(std::make_pair(kljuc, vrednost));
				mapa_stavki[kljuc] = lista_stavki.begin();

				// Ako je kapacitet kesa prekrsen, ukloni najdavnije korisceni par
				if (mapa_stavki.size() > kapacitet) {
					auto last = std::prev(lista_stavki.end());
					mapa_stavki.erase(last->first);
					lista_stavki.pop_back();
				}
			}

			/* Vraca vrednost za dati kljuc i oznacava ga kao najskorije koriscenog */
			const V& uzmi(const K& kljuc)
			{
				auto it = mapa_stavki.find(kljuc);
				if (it == mapa_stavki.end()){
					throw std::range_error("Nema trazenog kljuca u kesu");
				}

				// Premesti par na pocetak liste (oznaci ga kao najvise koriscenog)
				lista_stavki.splice(lista_stavki.begin(), lista_stavki, it->second);

				return it->second->second;
			}

			/* Proverava da li kes sadrzi dati kljuc */
			bool postoji(const K& kljuc) const
			{
				return mapa_stavki.find(kljuc) != mapa_stavki.end();
			}

		private:
			std::list<Par> lista_stavki;
			std::unordered_map<K, ListIt> mapa_stavki;
			size_t kapacitet;
	};
};

int main(void)
{
	int n; std::cin >> n;

	matf::LRU_kes<int, int> kes(n);

	char op;

	while(std::cin >> op) {
		if (op == 's') {
			int k, v; std::cin >> k >> v;
			kes.stavi(k, v);
		} else if (op == 'u') {
			int k; std::cin >> k;
			if (kes.postoji(k)) {
				int v = kes.uzmi(k);
				std::cout << k << std::endl;
			} else {
				std::cerr << "Kljuc nije u kesu" << std::endl;
			}
		}
	}

	return 0;
}