#include #include #include using namespace std; // LList { template struct elem_link1 { T inf; elem_link1 *link; }; template class LList { public: LList(); ~LList(); LList(LList const &); LList& operator=(LList const &); bool empty() const; void IterStart(elem_link1* = NULL); elem_link1* Iter(); void ToEnd(T const &); void InsertAfter(elem_link1 *, T const &); void InsertBefore(elem_link1 *, T const &); void DeleteElem(elem_link1 *, T &); int DeleteAfter(elem_link1 *, T &); int DeleteBefore(elem_link1 *, T &); int length(); void concat(LList const &); void reverse(); void print(); private: elem_link1 *Start, *End, *Current; void DeleteList(); void CopyList(LList const &); }; template LList::LList() { Start = End = Current = NULL; } template LList::~LList() { DeleteList(); } template LList::LList(LList const &r) { CopyList(r); } template LList& LList::operator=(LList const &r) { if (this != &r) { DeleteList(); CopyList(r); } return *this; } template void LList::DeleteList() { if (Start) { elem_link1 *p; while (Start) { p = Start; Start = Start->link; delete p; } End = NULL; } } template void LList::CopyList(LList const &r) { Start = End = NULL; elem_link1 *p = r.Start; while (p) { ToEnd(p->inf); p = p->link; } } template bool LList::empty() const { return Start == NULL; } template void LList::IterStart(elem_link1 *p) { if (p) Current = p; else Current = Start; } template elem_link1* LList::Iter() { elem_link1 *p = Current; if (Current) Current = Current->link; return p; } template int LList::length() { int n = 0; IterStart(); while (Iter()) n++; return n; } template void LList::ToEnd(T const &x) { Current = End; End = new elem_link1; End->inf = x; End->link = NULL; if (Current) Current->link = End; else Start = End; } template void LList::InsertAfter(elem_link1 *p, T const &x) { elem_link1 *q = new elem_link1; q->inf = x; q->link = p->link; if (p == End) End = q; p->link = q; } template void LList::InsertBefore(elem_link1 *p, T const &x) { elem_link1 *q = new elem_link1; *q = *p; p->inf = x; p->link = q; if (End == p) End = q; } template int LList::DeleteAfter(elem_link1 *p, T &x) { if (p == End) return 0; elem_link1 *q = p->link; x = q->inf; p->link = q->link; if (End == q) End = p; delete q; return 1; } template void LList::DeleteElem(elem_link1 *p, T &x) { if (p == Start) { x = p->inf; if (Start == End) { Start = NULL; End = NULL; delete p; } else { Start = Start->link; delete p; } } else { elem_link1 *q = Start; while (q->link != p) q = q->link; DeleteAfter(q,x); } } template int LList::DeleteBefore(elem_link1 *p, T &x) { if (p == Start) return 0; elem_link1 *q = Start; while (q->link != p) q = q->link; DeleteElem(q,x); return 1; } template void LList::concat(LList const &L) { elem_link1 *p = L.Start; while (p) { ToEnd(p->inf); p = p->link; } } template void LList::reverse() { LList L; elem_link1 *p = Start; if (p) { L.ToEnd(p->inf); p = p->link; while (p) { L.InsertBefore(L.Start, p->inf); p = p->link; } } *this = L; } template void LList::print() { elem_link1 *p = Start; while (p) { cout<< p->inf <<" "; p = p->link; } cout<<"\n"; } // LList } //-------------------------------------------------- // graph { template class graph { public: void addTop(const T&); void deleteTop(const T&); void addRib(const T&, const T&); void deleteRib(const T&, const T&); bool top(const T&); bool rib(const T&, const T&); bool empty() const; elem_link1* point(const T&); LList vertexes(); void print(); private: LList< LList > g; }; // включва а като връх на неявния граф template void graph::addTop(const T& a) { // създаване на линеен списък, съдържащ елемента a LList l; l.ToEnd(a); // включване на върха a към графа g.ToEnd(l); } // изключва върха а неявния граф template void graph::deleteTop(const T& a) { // обхождане на графа с цел изтриване на всички // ребра от произволен връх до върха a g.IterStart(); elem_link1 >* p = g.Iter(), *r; while(p) { p->inf.IterStart(); elem_link1* q = p->inf.Iter(); if (rib(q->inf, a)) deleteRib(q->inf, a); p = p->link; } // изтриване на линейния списък, представящ // върха a и неговите наследници g.IterStart(); elem_link1* q; do { r = g.Iter(); r->inf.IterStart(); q = r->inf.Iter(); } while(q->inf != a); // a е връх на графа LList x; g.deleteElem(r, x); } // включва ребро от върха a до върха b на неявния граф template void graph::addRib(const T& a, const T& b) { // намиране на указател към върха a на графа elem_link1* q = point(a), // намира указател към върха a * p; // включване на върха b в списъка от наследниците на върха a p = new elem_link1; //assert(p != NULL); p->inf = b; p->link = q->link; q->link = p; } // изключва реброто от върха a до върха b на неявния граф template void graph::deleteRib(const T& a, const T& b) { g.IterStart(); elem_link1 > *p; elem_link1 *q; do { p = g.Iter(); p->inf.IterStart(); q = p->inf.Iter(); } while (q->inf != a); q = q->link; // намиране на указател към наследника b на върха a while(q->inf != b) q = q->link; T x; p->inf.deleteElem(q, x); } // проверява дали a е връх на неявния граф template bool graph::top(const T& a) { if(g.empty()) return false; g.IterStart(); elem_link1 > *p = g.Iter(); elem_link1 *q; do { p->inf.IterStart(); q = p->inf.Iter(); p = p->link; } while(q->inf != a && p); return q->inf == a; } // проверява дали има ребро от върха a до върха b template bool graph::rib(const T& a, const T& b) { elem_link1* p = point(a); // намира указател към върха a p = p->link; while (p && p->inf != b) p = p->link; return p != NULL; } // проверява дали неявният граф е празен template bool graph::empty() const { return g.empty(); } // намира указател към върха a на графа template elem_link1* graph::point(const T& a) { g.IterStart(); elem_link1 > *p; elem_link1 *q; do { p = g.Iter(); p->inf.IterStart(); q = p->inf.Iter(); } while(q->inf != a); return q; } // връща списък от върховете на неявния граф template LList graph::vertexes() { LList l; g.IterStart(); elem_link1 > *p = g.Iter(); while(p) { p->inf.IterStart(); elem_link1* q = p->inf.Iter(); l.ToEnd(q->inf); p = p->link; } return l; } // извежда неявния граф template void graph::print() { g.IterStart(); elem_link1 > *p = g.Iter(); while (p) { p->inf.print(); p = p->link; } cout << endl; } // graph } //---------------------------------------------------- // // Задача 0: да се зареди граф от поток // // Избираме следното представяне: // първо се записва броя N на върховете // после за всеки връх k следва следната информация: // - брой на наследниците M[k] // - спиисък на наследниците a[1] a[2] ... a[M[k]] // // в горното представяне се предполага, че стойностите // на върховете са със стойности 1,2,...,N template void createGraph(graph & g, istream & is) { int ntops; is >> ntops; for(size_t k=1; k!=ntops+1; ++k) g.addTop(k); for(size_t k=1; k!=ntops+1; ++k) { int top; is >> top; size_t nribs; is >> nribs; for(size_t l=0; l> ribOtherEnd; g.addRib(top,ribOtherEnd); cerr << "adding rib (" << top <<"," << ribOtherEnd <<")" << endl; } } } // Задача 0,5 : да се състави функция, // която проверява дали една стойности а е // елемент от списъка l template bool isMember(T a, LList l) { l.IterStart(); while(elem_link1 * p = l.Iter()) if(p->inf == a) return true; return false; } // // 4: Да се състави функция, която // връща списък на родителите на върха child // в графа g // template LList getParents(T child, graph g) { LList rtn; LList l = g.vertexes(); l.IterStart(); while(elem_link1 * p = l.Iter()) if(g.rib(p->inf,child)) rtn.ToEnd(p->inf); return rtn; } // // 5: Път в граф // template LList DFS(T start, T end, graph g, LList pathSoFar=LList()) { pathSoFar.ToEnd(start); if(start==end) { return pathSoFar; } // следва неефективна, но проста реализация на намиране // на всички наследници на връх LList l = g.vertexes(); l.IterStart(); while(elem_link1 * p = l.Iter()) if(g.rib(start,p->inf)) if(!isMember(p->inf,pathSoFar)) { LList path=DFS(p->inf,end,g,pathSoFar); if(!path.empty()) return path; } return LList(); } // следващите задачи са за домашно // 5,5: Цикъл в граф, съдържащ връх template LList Cycle(T top, graph g) { // пътища от всички наследници на top до top } // // 6: Всички пътища в граф, които започват от даден връх // template LList DFSall(T start, T end, graph g, LList pathSoFar=LList(), LList> & allPaths=LList>()) { // вместо да връщаме пътя, го прибавяме в allPaths // забележка : на по-стари реализации на езика // трябва да се пише LList > вместо LList> } // 6,5: Всички цикли в граф, които съдържат връх, // а елементите им са четни числа и при това // разликата между максималния и минималния // елемент не е с повече от 30% по-голяма от // средноаритметичната стойност на неотрицателните // стойности на върхове във цикъла ;) // 7: Въпрос(*) : в метода deleteTop на graph се вика метод // deleteElem на LList, а истинското име на метода // е DeleteElem. Въпреки това, тази програма се компилира // без грешка. Защо? int main() { char cgraph[] = "9 " "1 1 2 " "2 3 3 4 5 " "3 1 6 " "4 1 7 " "5 2 8 9 " "6 1 7 " "7 1 8 " "9 0 "; graph g; istrstream iss(cgraph); createGraph(g,iss); cout << isMember(1,g.vertexes()) << endl; cout << isMember(12,g.vertexes()) << endl; cout << "---------------------" << endl; getParents(8,g).print(); cout << "---------------------" << endl; DFS(2,8,g).print(); cout << "---------------------" << endl; return 0; }