#ifndef LISTA_H #define LISTA_H #include #include // Jednostruko povezana lista iz glave 4. // // Lista je vlasnik svojih cvorova: alocira ih sa new, a oslobadja ih // destruktor. Kopiranje je zabranjeno; duboko kopiranje prikazano je samo // u glavi 3, na primeru dinamickog niza. // // Tip T mora da podrzava kopiranje. Funkcije pronadji i obrisi(x) dodatno // zahtevaju operatore == i !=, a umetni_sortirano i ucesljaj operatore // < i <=. // // Invarijanta: // Ako se krene od pocetak_ i prate pokazivaci sledeci, posle tacno // velicina_ cvorova stize se do nullptr. Svaki cvor na tom putu alocirala // je lista i nijedan se ne pojavljuje dva puta. template struct Cvor { T podatak; Cvor* sledeci; Cvor(const T& p, Cvor* s) : podatak(p), sledeci(s) {} }; template class Lista { public: Lista() : pocetak_(nullptr), velicina_(0) {} ~Lista(); Lista(const Lista&) = delete; Lista& operator=(const Lista&) = delete; bool prazna() const { return pocetak_ == nullptr; } std::size_t velicina() const { return velicina_; } Cvor* pocetak() const { return pocetak_; } void dodaj_na_pocetak(const T& x); void umetni_iza(Cvor* c, const T& x); void umetni_ispred(Cvor* c, const T& x); void umetni_sortirano(const T& x); void obrisi_sa_pocetka(); void obrisi_iza(Cvor* c); bool obrisi(const T& x); void isprazni(); Cvor* pronadji(const T& x) const; void ucesljaj(Lista& druga); private: Cvor* pocetak_; std::size_t velicina_; }; // ----------------------------------------------------------------------------- // Definicije funkcija clanica // ----------------------------------------------------------------------------- template Lista::~Lista() { isprazni(); } template void Lista::dodaj_na_pocetak(const T& x) { Cvor* novi = new Cvor(x, pocetak_); pocetak_ = novi; ++velicina_; } // c mora da pokazuje na cvor ove liste. template void Lista::umetni_iza(Cvor* c, const T& x) { assert(c != nullptr); Cvor* novi = new Cvor(x, c->sledeci); c->sledeci = novi; ++velicina_; } // Novi cvor se umece iza c, a podaci se rasporede tako da redosled bude // kao da je umetnut ispred c. Posle poziva c pokazuje na novi element. template void Lista::umetni_ispred(Cvor* c, const T& x) { assert(c != nullptr); umetni_iza(c, c->podatak); c->podatak = x; } // Ako je lista bila sortirana, ostaje sortirana. template void Lista::umetni_sortirano(const T& x) { if (prazna() || x <= pocetak_->podatak) { dodaj_na_pocetak(x); return; } Cvor* prethodni = pocetak_; while (prethodni->sledeci != nullptr && prethodni->sledeci->podatak < x) prethodni = prethodni->sledeci; umetni_iza(prethodni, x); } template void Lista::obrisi_sa_pocetka() { assert(!prazna()); Cvor* stari = pocetak_; pocetak_ = stari->sledeci; // pre delete, dok je stari jos ispravan delete stari; --velicina_; } template void Lista::obrisi_iza(Cvor* c) { assert(c != nullptr); Cvor* stari = c->sledeci; assert(stari != nullptr); c->sledeci = stari->sledeci; delete stari; --velicina_; } // Brise prvo pojavljivanje x. Vraca false ako x nije u listi. template bool Lista::obrisi(const T& x) { if (prazna()) return false; if (pocetak_->podatak == x) { obrisi_sa_pocetka(); return true; } Cvor* prethodni = pocetak_; while (prethodni->sledeci != nullptr && prethodni->sledeci->podatak != x) prethodni = prethodni->sledeci; if (prethodni->sledeci == nullptr) return false; obrisi_iza(prethodni); return true; } template void Lista::isprazni() { while (!prazna()) obrisi_sa_pocetka(); } template Cvor* Lista::pronadji(const T& x) const { for (Cvor* p = pocetak_; p != nullptr; p = p->sledeci) if (p->podatak == x) return p; return nullptr; } // Ucesljava dve sortirane liste. Posle poziva ova lista sadrzi sve // elemente, a druga je prazna. Cvorovi se ne kopiraju, samo se drugacije // povezuju. template void Lista::ucesljaj(Lista& druga) { Cvor* a = pocetak_; Cvor* b = druga.pocetak_; Cvor* poslednji = nullptr; // poslednji cvor rezultata while (a != nullptr && b != nullptr) { Cvor* manji; if (a->podatak <= b->podatak) { manji = a; a = a->sledeci; } else { manji = b; b = b->sledeci; } // Prvi cvor rezultata nema prethodnika, pa se menja pocetak_. if (poslednji == nullptr) pocetak_ = manji; else poslednji->sledeci = manji; poslednji = manji; } Cvor* ostatak = (a != nullptr) ? a : b; if (poslednji == nullptr) pocetak_ = ostatak; else poslednji->sledeci = ostatak; // Svaki cvor sme da pripada samo jednoj listi, inace bi ga oba // destruktora oslobodila. velicina_ += druga.velicina_; druga.pocetak_ = nullptr; druga.velicina_ = 0; } #endif