STL - Untermenge Von STL-Container "List"
-
Hallo,
So, es geht um folgendes:
ich muss leider STL Conteiner-Klasse "List" selbst implementieren als z.B. mit der Name "Clist" und muss selber alle memberfunktion
· list::assign
· list::back
· list::begin
· list::clear
· list::empty
· list::end
· list::erase
· list::front
· list::get_allocator
· list::insert
· list::max_size
· list::merge
· list::operator=
· list::pop_back
· list::pop_front
· list::push_back
· list::push_front
· list::rbegin
· list::remove
· list::remove_if
· list::rend
· list::resize
· list::reverse
· list::size
· list::sort
· list::splice
· list::swap
· list::uniqueimplementieren. Kann jemand mir vielleicht helfen, ob es dafür eine Quelle gibt oder eine Idee vielleicht, wie ich diese Aufgabe lösen kann?? Die Aufgaben von Funktionen sind schon klar. Aber selbst implementieren kann ich leider nicht

Noch mal meine Aufgabe:
list::unique() -> Clist:unique()
usw. für alle member Funktionen(oben) von STL Containerklasse "List".
Viele Grüße
Strong
-
die Implementierungen kannst du alle hier nachlesen:
http://www.cplusplus.com/reference/algorithm
-
Die sind die Algorithmen. Ich brauche die Implementierung von Member Fuktionen von Klasse List.
-
// +--------------------------------------------------------------------------- // + Datei: SWE3/2007.07/rotate/Clist.hpp // + AutorIn: // + Beschreibung: Die Schnittstelle zu Clist<T> // + Revision: 2007/06/22 // +--------------------------------------------------------------------------- #if !defined(Clist_hpp) #define Clist_hpp // --- Zusätzliche Deklarationen #include <cstddef> #include <iterator> // für std::bidirectional_iterator_tag // +--------------------------------------------------------------------------- // + namespace swe3 // + // +--------------------------------------------------------------------------- namespace swe3 { // +--------------------------------------------------------------------------- // + Vorwärtsdeklaration der Listenelemente - als Schablone. // + // +--------------------------------------------------------------------------- template <typename T> class ClistElem; // +--------------------------------------------------------------------------- // + Clist<T> - eine funktionelle Untermenge von std::list<T> // + 2007/06/12 // +--------------------------------------------------------------------------- template <typename T> class Clist { public: // Die STL Typen - neu typedef T value_type; typedef value_type *pointer; typedef value_type const *const_pointer; typedef value_type &reference; typedef value_type const &const_reference; typedef std::ptrdiff_t difference_type; typedef std::size_t size_type; typedef void reverse_iterator; // nicht definiert typedef void const_reverse_iterator; // nicht definiert typedef void allocator; // nicht definiert // iterator class iterator { public: // Die STL Typen - neu typedef typename Clist<T>::value_type value_type; typedef typename Clist<T>::pointer pointer; typedef typename Clist<T>::reference reference; typedef typename Clist<T>::difference_type difference_type; typedef std::bidirectional_iterator_tag iterator_category; // Kon- und Destruktoren iterator() throw(); iterator(iterator const&) throw(); ~iterator() throw(); // In- und Dekrement-Operatoren iterator& operator++() throw(); // Präfix iterator operator++(int) throw(); // Postfix iterator& operator--() throw(); iterator operator--(int) throw(); // Zuweisungsoperator iterator& operator=(iterator const&) throw(); // Vergleichsoperatoren bool operator==(iterator const&) const throw(); bool operator!=(iterator const&) const throw(); // Zugriff auf die Elemente im Vektor T &operator*(); T *operator->(); private: ClistElem<T> *prev_, *current_, *next_; friend class Clist<T>; }; // const_iterator class const_iterator { public: // Die STL Typen - neu typedef typename Clist<T>::value_type const value_type; typedef typename Clist<T>::const_pointer pointer; typedef typename Clist<T>::const_reference reference; typedef typename Clist<T>::difference_type difference_type; typedef std::bidirectional_iterator_tag iterator_category; // Kon- und Destruktoren const_iterator() throw(); const_iterator(const_iterator const&) throw(); const_iterator(iterator const&) throw(); ~const_iterator() throw(); // In- und Dekrement-Operatoren const_iterator& operator++() throw(); // Präfix const_iterator operator++(int) throw(); // Postfix const_iterator& operator--() throw(); const_iterator operator--(int) throw(); // Zuweisungsoperator const_iterator& operator=(const_iterator const&) throw(); // Vergleichsoperatoren bool operator==(const_iterator const&) const throw(); bool operator!=(const_iterator const&) const throw(); // Zugriff auf die Elemente im Vektor T const &operator*() const; T const *operator->() const; private: ClistElem<T> *prev_, *current_, *next_; friend class Clist<T>; }; // Kon- und Destruktoren Clist() throw(); Clist(Clist<T> const&); Clist(size_type, T const &); ~Clist(); // Den Zustand abfragen size_t size() const throw(); bool empty() const throw(); // Elemente einfügen, löschen (die "modifiers") void push_back(T const&); void pop_back(); void push_front(T const&); void pop_front(); iterator insert(iterator position, T const&); void insert(iterator position, size_type, T const&); iterator erase(iterator position); iterator erase(iterator first, iterator last); void clear(); // Zugriff auf einzelne Elemente (kein wahlfreier Zugriff) T &front(); T const &front() const; T &back(); T const &back() const; // Operationen auf ganzen Listen - neu mit sort Clist<T>& operator=(Clist<T> const &); void swap(Clist<T>&) throw(); // Die speziellen Sortieralgorithmen für Clist<T> // die zweite Form als sogenannte Methoden-Schablone // (member template) void sort(); template <typename Compare> void sort(Compare); // begin, end iterator begin() throw(); const_iterator begin() const throw(); iterator end() throw(); const_iterator end() const throw(); private: // Die Datenelemente ClistElem<T> *head_, *tail_; size_type size_; // Hilfsmethoden void del_(); }; // +--------------------------------------------------------------------------- // + void Clist<T>::sort(char const *) - Spezialisierung für nullterminierte // + Zeichenketten. // + // +--------------------------------------------------------------------------- template < > void Clist<char const *>::sort(); // +--------------------------------------------------------------------------- // + ClistElem<T> - die Listenelemente einer doppelt verketteten Liste mit // + Anker. Hier definiert für Zugriff durch den Testtreiber. // + 2007/05/09 // +--------------------------------------------------------------------------- template <typename T> class ClistElem { private: // Elemente anlegen nur für "friends" explicit ClistElem(T const & =T()); private: // Die Datenelemente ClistElem<T> *prev_, *next_; T value_; // Hilfsfunktionen void link_(ClistElem<T> *, bool append =true) throw(); void link_(ClistElem<T> *, ClistElem<T> *, bool append=true) throw(); void unlink_() throw(); void unlink_(ClistElem<T> *) throw(); private: // Keine Kopien ClistElem(const ClistElem<T>&); ClistElem<T>& operator=(const ClistElem<T>&); friend class Clist<T>; friend class Clist<T>::iterator; friend class Clist<T>::const_iterator; }; // +--------------------------------------------------------------------------- // + operator==(Clist<T> const&, Clist<T> const&) // + externer Operator entsprechend den STL Gepflogenheiten // + ------------------------------------------------------------------------ template <typename T> inline bool operator==(Clist<T> const &a, Clist<T> const &b) { if (a.size() != b.size()) return false; typename Clist<T>::const_iterator aiter(a.begin()), biter(b.begin()); for( ; aiter!=a.end() && biter!=b.end() && *aiter==*biter; ++aiter, ++biter); return aiter==a.end() && biter==b.end(); } // +--------------------------------------------------------------------------- // + operator!=(Clist<T> const&, Clist<T> const&) // + externer Operator entsprechend den STL Gepflogenheiten // + // +--------------------------------------------------------------------------- template <typename T> inline bool operator!=(Clist<T> const &a, Clist<T> const &b) { return !(a==b); } } // namespace // --- Die Implementierungsdatei einbinden ------------------------------------ #include "Clist.cpp" // #endif // // Ende der Datei //
-
//+--------------------------------------------------------------------------- //+ Datei: SWE3/Clist.cpp //+ //+ Beschreibung: Implementierung der Klassenschablone Clist<T> als //+ Untermenge von std::list<T>. //+ KorrektorIn: //+ //+ Revision: - Details am Ende der Datei //+--------------------------------------------------------------------------- #if !defined(Clist_cpp) #define Clist_cpp #include <cstddef> #include <stdexcept> #include "Clist.hpp" // --- using directives using namespace std; // +--------------------------------------------------------------------------- // + namespace swe3 // + // +--------------------------------------------------------------------------- namespace swe3 { // +--------------------------------------------------------------------------- // + Clist::Clist() - Standardkonstruktor // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> Clist<T>::Clist() throw() : head_(0), tail_(0), size_(0) {} // +--------------------------------------------------------------------------- // + Clist<T>::Clist(Clist const&) - Kopierkonstruktor; wird vom Zuweisungs- // + operator benutzt zur einfacheren Gewährleistung der "exception // + safety" - es wird eine vollständige Kopie erzeugt oder nur ein // + leeres Objekt. Auftretende Ausnahmen werden weitergereicht. // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> Clist<T>::Clist(Clist<T> const & list ) : head_( 0 ), tail_( 0 ), size_( 0 ) { //Liste leer? if( list.empty() ) return; //Wenn Objekt gleiche ist, muss nichts getan werden. if( this == &list ) return; try{ for(ClistElem<T> *elem=list.head_; elem ; elem=elem->next_) push_back(elem->value_); }catch(...) { del_(); throw("Kopierkonstruktor\n"); } } // +--------------------------------------------------------------------------- // + Clist<T>::Clist(size_t n, T const &s) - neue Liste mit n gleichen // + Elementen. Exception safety wie beim Kopierkonstruktor: Es wird // + eine vollständige Liste mit n Elementen angelegt oder eine leere // + Liste. Auftretende Ausnahmen werden weitergereicht. // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> Clist<T>::Clist(std::size_t n, T const & s ): head_( 0 ), tail_( 0 ), size_( 0 ) { //Wenn n null ist if( !n ) return; try{ for(size_t i=0; i<n; ++i) push_back(s); }catch(...) { del_(); throw("Clist(size_t n, T const &s)\n"); } } // +--------------------------------------------------------------------------- // + Clist<T>::~Clist() - Destruktor - wirft keine Ausnahmen, falls ~T keine // + Ausnahmen wirft. // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> Clist<T>::~Clist() { //Destruktor ruft Funktion clear() auf clear(); } // +--------------------------------------------------------------------------- // + Clist<T>::size() const throw() - liefert die Anzahl enthaltener Elemente // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> size_t Clist<T>::size() const throw() { //Anzahl von Elementen der Listen zurückgeben return size_; } // +--------------------------------------------------------------------------- // + Clist<T>::empty() const throw() - liefert true, falls die Liste leer // + ist, sonst false, // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> bool Clist<T>::empty() const throw() { return !size_; } // +--------------------------------------------------------------------------- // + Clist<T>::push_back(T const&) - neues Element am Ende einfügen // + Exception safe: Einfügen oder die Liste unverändert lassen. // + Die Funktion kann bei Mangel an freiem Speicher Ausnahmen werfen, // + bzw. falls der T Konstruktor eine Ausnahme wirft. // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> void Clist<T>::push_back(T const & s) { //dynamisch (mit *elem new ClistElem<T>(s)) erzeugen ClistElem<T> *elem = new ClistElem<T>( s ); //Wenn es Speicherplatz nicht gibt if( !elem ) throw bad_alloc(); //Wenn noch kein Element eingefügt if( !head_ ) //zeigt head auf das erste Element head_ = elem; else //das neue Element mit dem letzten Element (tail) verlinken (link_(elem)) tail_->link_( elem ); //Tail zeigt auf auf das neue Element tail_ = elem; //Size eins erhoehen, da ein Element mehr in der Liste ++size_; } // +--------------------------------------------------------------------------- // + Clist<T>::pop_back() - das Element am aktuellen Ende löschen. // + Die Funktion wirft keine Ausnahmen, falls ~T keine wirft. // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> void Clist<T>::pop_back() { //Wenn tail nichts zeigt, if( !tail_ ) throw out_of_range("pop_back()-Clist ist leer"); //Neue ClistElem initialisieren mit tail-prev ClistElem<T> *letzte = tail_->prev_; //Letze Element muss aus der Liste unlinken tail_->unlink_(); //tail zeigt auf letzte tail_ = letzte; //Wenn tail =0, dann head ist auch =0 if( !tail_ ) head_ = 0; //Size eins erniedrigen, da ein Element weniger in der Liste --size_; } // +--------------------------------------------------------------------------- // + Clist<T>::push_front(T const&) - neues Element am Anfang einfügen // + Exception safe: Einfügen oder die Liste unverändert lassen. // + Die Funktion kann bei Mangel an freiem Speicher Ausnahmen werfen, // + bzw. falls der T Konstruktor eine Ausnahme wirft (vgl. push_back). // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> void Clist<T>::push_front(T const&s) { //dynamisch (mit *elem new ClistElem<T>(s)) erzeugen ClistElem<T> *elem = new ClistElem<T>( s ); //Wenn es Speicherplatz nicht zur Verfuegung steht if( !elem ) throw bad_alloc(); //Wenn noch kein Element eingefügt if( !head_ ) { //zeigt head auf das erste Element head_ = elem; //tail ist head tail_ = head_; } else //ansonsten vor head_ linken deswegen 2.Parameter false head_->link_( elem, false ); //Neues head_ ist elem head_ = elem; //Size eins erhoehen, da ein Element mehr in der Liste ++size_; } // +--------------------------------------------------------------------------- // + Clist<T>::pop_front() - das Element am aktuellen Anfang löschen. // + Die Funktion wirft keine Ausnahmen, falls ~T keine wirft. // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> void Clist<T>::pop_front() { //Wenn head nichts zeigt, if( !head_ ) throw out_of_range("pop_front() CList is empty \n"); //Neue ClistElem initialisieren mit head->next ClistElem<T> *erste = head_->next_; //Letze Element muss aus der Liste unlinken head_->unlink_(); //head mit erste zuweisen head_ = erste; //wenn head nichts zeigt, dann tail ist 0 if( !head_ ) tail_ = 0; //Size eins erniedrigen, da ein Element weniger in der Liste --size_; } // +--------------------------------------------------------------------------- // + Clist<T>::insert(iterator pos, T const &t) - ein Element einfügen // + vor pos. Gibt einen Iterator zum neu eingefügten Element zurück. // + Exception safe: Einfügen oder die Liste unverändert lassen. // + Die Funktion kann bei Mangel an freiem Speicher Ausnahmen werfen, // + bzw. falls der T Konstruktor eine Ausnahme wirft (wie push_back). // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> typename Clist<T>::iterator Clist<T>::insert(Clist<T>::iterator pos, T const & t) { if( !pos.prev_ && !pos.next_ && pos.current_ != head_ ){ return typename Clist<T>::iterator(); } //Überprüfen, ob pos == begin() if (pos==begin()){ insert(pos, 1, t); return begin(); } //Überprüfen, ob pos == end() if( pos==end() ){ insert(pos, 1, t); return (--end()); } //Wenn in die Mitte der Liste else { insert(pos, 1, t); typename Clist<T>::iterator iter; iter.prev_ = pos.prev_; iter.current_ = pos.current_->prev_; iter.next_ = pos.current_; return iter; } } // +--------------------------------------------------------------------------- // + Clist<T>::insert(iterator pos, size_type n, T const &t) - n neue // + Element mit Wert t vor pos einfügen. // + Exception safe: Einfügen oder die Liste unverändert lassen. // + Die Funktion kann bei Mangel an freiem Speicher Ausnahmen werfen, // + bzw. falls der T Konstruktor eine Ausnahme wirft (wie insert). // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> void Clist<T>::insert(iterator pos, size_type n, T const & t) { //Wenn n = 0 ist, muss nichts zurückgeben if (!n) return; //Temporaer Clist Element erzeugen durch Clist<T> tmp(n,t) Clist<T> temp(n, t); //Wenn aktuelle Element->empty() if (this->empty()) { *this = temp; return; } //Wenn pos == begin() if (pos == begin()) { pos.current_->link_(temp.head_, temp.tail_, false); head_ = temp.head_; } //Wenn pos == end() else if (pos == end()) { pos.prev_->link_(temp.head_, temp.tail_, true); tail_ = temp.tail_; } else pos.current_->link_(temp.head_, temp.tail_, false); //size muss n mal erhöht werden size_ = n + size_; //Temporaer Objekt loeschen(head, tail, size) temp.head_ = temp.tail_ = 0; temp.size_ = 0; } // +--------------------------------------------------------------------------- // + Clist<T>::erase(iterator pos) - das Element beim Iterator pos löschen. // + Rückgabewert ist ein Iterator zum ersten Element nach pos, end() falls // + das Element am Ende der Liste gelöscht wurde (pos==--end()). // + Die Funktion wirft keine Ausnahmen, falls ~T keine wirft. // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> typename Clist<T>::iterator Clist<T>::erase(iterator pos) { if( !pos.prev_ && !pos.next_ && pos.current_ != head_ ){ return typename Clist<T>::iterator(); } if( (pos==--begin()) || (pos==end()) ) return typename Clist<T>::iterator(); //Am Anfang der Liste kann pop_front() verwendet werden //Vorteil: pop_front() setzt auch den head_ Zeiger entsprechend //bzw. passt die Groesse an if( pos == begin() ) { pop_front(); return begin(); } //Am Ende der Liste kann pop_back() verwendet werden //Vorteil: pop_back() setzt auch den tail_ Zeiger entsprechend //bzw. passt die Groesse an if( pos == --end() ) { pop_back(); return end(); } //Wenn es nicht zu loeschen ist, dann leere Iterator zurück //irgendwo in der Mitte der Liste loeschen -> unlink_() Funktion //für ein Element der Liste else { typename Clist<T>::iterator iter; iter.prev_ = pos.prev_; iter.current_ = pos.next_; iter.next_= pos.next_->next_; //pos.current unlinken pos.current_->unlink_(); //Size eins erniedrigen, da ein Element weniger in der Liste --size_; return iter; } } // +--------------------------------------------------------------------------- // + Clist<T>::erase(iterator first, iterator last) - die Elemente im Inter- // + vall [frst,lst) löschen. Rückgabewert ist ein Iterator zum ersten // + Element nach den gelöschten Elementen, end() falls auch das Element // + am Ende der Liste gelöscht wurde (last==end()). // + Die Funktion wirft keine Ausnahmen, falls ~T keine wirft. // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> typename Clist<T>::iterator Clist<T>::erase(iterator first, iterator last) { //Wenn first ist gleich last ist, dann last zurückgeben if (first==last) return last; //2 ClistElem<T> temporaer element erzeugen und erste mit first.current, //zweite mit last.prev_ initialisieren ClistElem<T> *p(first.current_), *q(last.prev_); // head_, tail_ if (head_==p) head_=q->next_; if (tail_==q) tail_=p->prev_; // Aushaengen p->unlink_(q); // garbage collection q->next_ = 0; size_t anz(0); ClistElem<T> *n(p->next_); while (p) { ++anz; delete p; p=n; n=(n)?n->next_:0; } //size ist size - anz size_ -= anz; //Rueckgabewert ist iterator typename Clist<T>::iterator iter; iter.current_ = last.current_; iter.next_ = last.next_; iter.prev_=first.prev_; return iter; } // +--------------------------------------------------------------------------- // + Clist<T>::clear - alles löschen. Die Funktion wirft keine Ausnahmen, // + falls ~T keine wirft. // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> void Clist<T>::clear(){ //Solange tail_ darauf zeigt, durch pop_back() von hinten while(tail_) pop_back(); } // +--------------------------------------------------------------------------- // + Clist<T>::front() - Zugriff zum ersten Element // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> T& Clist<T>::front(){ if(!head_) throw("Front"); return head_->value_; } // +--------------------------------------------------------------------------- // + Clist<T>::front() const - Zugriff zum ersten Element // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> const T& Clist<T>::front() const { if(!head_) throw("Front"); return head_->value_; } // +--------------------------------------------------------------------------- // + Clist<T>::back() - Zugriff zum letzten Element // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> T& Clist<T>::back(){ if(!tail_) throw("Front"); return tail_->value_; } // +--------------------------------------------------------------------------- // + Clist<T>::back() const - Zugriff zum letzten Element // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> const T& Clist<T>::back() const { if(!tail_) throw("Front"); return tail_->value_; } // +--------------------------------------------------------------------------- // + Clist<T>::operator=(Clist const&) - Zuweisungsoperator. // + Exception safe: Die Zuweisung wird vollständig durchgeführt, oder // + die Zielliste (lvalue) wird nicht verändert. Auftretende Ausnahmen // + werden weitergegeben. // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> Clist<T>& Clist<T>::operator=(Clist<T> const &list){ //wenn this gleich &list dann gibt einfach this zurück if( this == &list ) return *this; //Neue Clist erzeugen und mit list initialisieren Clist<T> listCopy( list ); //swap funktion aufrufen um neue Clist zu vertauschen //swap als Parameter mit neuen Element aufrufen swap( listCopy ); // Ende this zurück return *this; } // +--------------------------------------------------------------------------- // + Clist<T>::swap throw() - Inhalte tauschen in O(1) Zeit , dh. unab- // + hängig von der Länge der Listen. // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> void Clist<T>::swap(Clist<T> & list )throw(){ //2 Elemente als temporaer vom Typ ClistElem<T> für head und tail ClistElem<T> *anfang = list.head_; ClistElem<T> *ende = list.tail_; size_t size = list.size_; //Memberdaten von List tauschen list.head_ = head_; list.tail_ = tail_; list.size_ = size_; //Neue werte von head,tail und size zuweisen head_ = anfang; tail_ = ende; size_ = size; } // +--------------------------------------------------------------------------- // + Clist<T>::sort() - die Liste sortieren mittels des < Operators für T. // + Als Algorithmus wird bubble-sort verwendet - nicht optimal! // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> void Clist<T>::sort()throw(){ for (ClistElem<T> *p(head_); p; p=p->next_) { for (ClistElem<T> *q(p->next_); q; q=q->next_) { if(q->value_ < p->value_) std::swap(p->value_,q->value_); } } } // +--------------------------------------------------------------------------- // + Clist<T>::sort(Compare comp) - die Liste sortieren nach der von comp // + bestimmten Ordung. Als Algorithmus wird bubble-sort verwendet. // + Eine Methoden-Schablone: template geschachtelt! // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> template <typename Compare> //sort() ist selbst ein template void Clist<T>::sort(Compare comp)throw() { for (ClistElem<T> *p(head_); p; p=p->next_) { for (ClistElem<T> *q(p->next_); q; q=q->next_) { if (comp(q->value_, p->value_)) std::swap(p->value_,q->value_); } } } // +--------------------------------------------------------------------------- // + Clist<char const *>::sort() - die Liste sortieren nach dem < Operator // + für T; Spezialisierung für const char * mit strcmp. // + Als Algorithmus wird bubble-sort verwendet - nicht optimal! // + , 20.12.2007 // +--------------------------------------------------------------------------- template < > inline void Clist<char const *>::sort()throw(){ for (ClistElem<char const *> *p(head_); p; p=p->next_) { for (ClistElem<char const *> *q(p->next_); q; q=q->next_) { if (strcmp(q->value_, p->value_) < 0) std::swap(p->value_,q->value_); } } } // +--------------------------------------------------------------------------- // + Clist<T>::begin() - Iterator auf den Anfang der Liste -> Rückgabewert iterator // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> typename Clist<T>::iterator Clist<T>::begin()throw(){ //Neu iterator definieren iterator it; //für neue iterator prev ist gleich Null it.prev_ = 0; //für neue iterator current ist gleich head it.current_ = head_; if (head_) it.next_ = head_->next_; else it.next_ = 0; //neue iterator zurueck geben return it; } // +--------------------------------------------------------------------------- // + Clist<T>::begin() const - Iterator auf den Anfang der Liste // + , 20.12.2007-> ist wie begin(), aber als const // + Kommentare: Wie iterator begin(), allerdings als const // +--------------------------------------------------------------------------- template <typename T> typename Clist<T>::const_iterator Clist<T>::begin() const throw(){ const_iterator it; it.prev_ = 0; it.current_ = head_; if (head_) it.next_ = head_->next_; else it.next_ = 0; return it; } // +--------------------------------------------------------------------------- // + Clist<T>::end() - Iterator auf erste Element "nach" dem Vektor: // + "off-the-end iterator" // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> typename Clist<T>::iterator Clist<T>::end()throw(){ //Neue Iterator it definieren iterator it; //it.prev ist gleich tail it.prev_ = tail_; //it.current und it.next ist gleich null it.current_ = it.next_ = 0; //Neue Iterator zurückgeben return it; } // +--------------------------------------------------------------------------- // + Clist<T>::end() const - Iterator auf erste Element "nach" dem Vektor: // + "off-the-end iterator" // + , 20.12.2007-> wie end(), aber als const // + Kommentare: Wie iterator end(), allerdings als const // +--------------------------------------------------------------------------- template <typename T> typename Clist<T>::const_iterator Clist<T>::end() const throw() { const_iterator iter; iter.prev_ = tail_; iter.current_ = iter.next_ = 0; return iter; } // +--------------------------------------------------------------------------- // + Clist<T>::del_() - alle Elemente einer Clist löschen. Die Methode // + arbeitet vom Ende her. Sie wirft keine Ausnahmen, falls ~T keine // + wirft. // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> void Clist<T>::del_() { //Solange tail was zeigt durch pop_back (von hinten) elemente loeshen while( tail_ ) this->pop_back(); } // +-------------------------------------------------------------------------- // + Implementierung von Iteratoren // + Innerhalb Clist Klasse gibt es auch andere Klassen wie z.B. class iterator und // + class const_iterator. Die müssen auch in Clist.cpp implementiert werden. // + A.Güclü Ercin, 20.12.2007 // +-------------------------------------------------------------------------- // +--------------------------------------------------------------------------- // + Clist<T>::iterator::iterator() - Standard-Konstruktor; die Einträge // + werden über begin() und end() gesetzt, bzw. über die In- und De- // + krement-Operatoren verändert // + Standard-Konstruktor setzt alle Member Daten(prev_,current_, next_) auf 0 // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> Clist<T>::iterator::iterator()throw(): prev_(0), current_(0), next_(0){ } // +--------------------------------------------------------------------------- // + Clist<T>::iterator::iterator(iterator const&) - Kopier-Konstruktor // + , 20.12.2007 // + Kopier-Konstruktor setzt alle Member Daten auf als parameter übergegebene Werte // + mit sich selbt z.B. prev(it.prev_) // +--------------------------------------------------------------------------- template <typename T> Clist<T>::iterator::iterator(iterator const &it) throw(): prev_( it.prev_ ),current_( it.current_ ), next_( it.next_ ) { } // +--------------------------------------------------------------------------- // + Clist<T>::iterator::~iterator() - Destruktor // + , 20.12.2007 // + Destruktor setzt alle Member Daten auf Null in Funktionskörper. // +--------------------------------------------------------------------------- template <typename T> Clist<T>::iterator::~iterator() throw() {prev_ = 0; current_ = 0; next_ = 0; } // +--------------------------------------------------------------------------- // + Clist<T>::iterator::operator++() - Inkrement, Präfix // + Keine Plausibilitätsprüfung! Spezielle Behandlung der Fälle "vor" und // + "nach" der Liste. // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> typename Clist<T>::iterator& Clist<T>::iterator::operator++()throw(){ if( current_ ){ prev_ = current_; current_ = next_; if( current_ ) next_ = current_->next_ ; else next_ = 0; } else if( next_ ){ // vor dem Anfang prev_ = 0; current_ = next_; if( current_ )next_ = current_->next_; else next_ = 0; } return *this; } // +--------------------------------------------------------------------------- // + Clist<T>::iterator::operator++(int) - Inkrement, Postfix // + Keine Plausibilitätsprüfung! // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> typename Clist<T>::iterator Clist<T>::iterator::operator++(int)throw(){ iterator it( *this ); ++( *this ); return it; } // +--------------------------------------------------------------------------- // + Clist<T>::iterator::operator--() - Dekrement, Präfix // + Keine Plausibilitätsprüfung! Spezielle Behandlung der Fälle "vor" und // + "nach" der Liste. // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> typename Clist<T>::iterator& Clist<T>::iterator::operator--()throw(){ if( current_ ){ next_ = current_; current_ = prev_; if( current_ ) prev_ = current_->prev_ ; else prev_ = 0; } else if( prev_ ){ next_ = 0; current_ = prev_; if( current_ ) prev_ = current_->prev_; else prev_ = 0; } return *this; } // +--------------------------------------------------------------------------- // + Clist<T>::iterator::operator--(int) - Dekrement, Postfix // + Keine Plausibilitätsprüfung! // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> typename Clist<T>::iterator Clist<T>::iterator::operator--(int)throw(){ iterator it( *this ); --(*this); return it; } // +--------------------------------------------------------------------------- // + Clist<T>::iterator::operator=(iterator const&) // + , 20.12.2007 // + "Operator =" setzt alle Member Daten auf als parameter übergegebene Werte // + mit sich selbt z.B. prev(it.prev_) und gibt *this zurück // +--------------------------------------------------------------------------- template <typename T> typename Clist<T>::iterator& Clist<T>::iterator::operator=(iterator const& it) throw(){ prev_ = it.prev_; current_ = it.current_; next_ = it.next_; return (*this); } // +---------------------------------------------------------------------------------- // + Clist<T>::iterator::operator==(iterator const&) - nur iteratoren zum // + selben Container können gleich sein! // + , 20.12.2007 // + Gibt true zurück wenn Member Daten gleich mit als parameter übergegebene // + Objekt ist. so z.B. prev_==it.prev_ && current_==it.current_ && next_==it.next_ // +----------------------------------------------------------------------------------- template <typename T> bool Clist<T>::iterator::operator==(iterator const & it ) const throw(){ return prev_==it.prev_ && current_==it.current_ && next_==it.next_; } // +--------------------------------------------------------------------------- // + Clist<T>::iterator::operator!=(iterator const&) // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> bool Clist<T>::iterator::operator!=(iterator const & it) const throw(){ return !( *this == it ); } // +--------------------------------------------------------------------------- // + Clist<T>::iterator::operator*() - Zugriff auf das Element, auf das der // + aktuelle Iterator "verweist". Die Plausibilitätskontrolle ist bei // + den gängigen STL Implementierungen nicht vorhanden wegen der Lauf- // + zeitverschlechterung. // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> T& Clist<T>::iterator::operator*(){ if ( ((!current_) && (!next_)) || ((!prev_) && (!current_)) ) throw out_of_range("*op bad iterator"); // (!current_) && (!next_) -> am hinteren Ende der Liste? // (!prev_) && (!current_) -> am vorderen Ende der Liste? return current_->value_; } // +--------------------------------------------------------------------------- // + Clist<T>::iterator::operator->() - Zugriff auf Elemente des Ts, // + auf den der aktuelle Iterator "verweist". // + Die Plausibilitätskontrolle ist bei den gängigen STL Implementierungen // + nicht vorhanden wegen der Laufzeitverschlechterung. // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> T* Clist<T>::iterator::operator->(){ if ( ((!current_) && (!next_)) || ((!prev_) && (!current_)) ) throw out_of_range("->op bad iterator"); //Erklärung siehe operator*() //(!current_) && (!next_) -> am hinteren Ende der Liste? //(!prev_) && (!current_) -> am vorderen Ende der Liste? return &(current_->value_); } // +--------------------------------------------------------------------------- // + Implementierung von Const_Iteratoren - class const_iterator // +--------------------------------------------------------------------------- // +--------------------------------------------------------------------------- // + Clist<T>::const_iterator::const_iterator() - Standard-Konstruktor; die // + Einträge werden über begin() const und end() const gesetzt, bzw. über // + die In- und Dekrement-Operatoren verändert // + , 20.12.2007 // + Standard-Konstruktor setzt alle Member Daten auf Null // +--------------------------------------------------------------------------- template <typename T> Clist<T>::const_iterator::const_iterator()throw(): prev_(0), current_(0), next_(0) {} // +--------------------------------------------------------------------------- // + Clist<T>::const_iterator::const_iterator(const_iterator const&) - // + Kopier-Konstruktor // + , 20.12.2007 // + wie oben bei der Klasse iterator-> Kopierkonstruktor // +--------------------------------------------------------------------------- template <typename T> Clist<T>::const_iterator::const_iterator(const_iterator const & it) throw(){ prev_ = it.prev_; current_ = it.current_; next_ = it.next_; } // +--------------------------------------------------------------------------- // + Clist<T>::const_iterator::const_iterator(iterator const&) - // + Konvertierung von iterator zu const_iterator // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> Clist<T>::const_iterator::const_iterator(iterator const & it) throw() { prev_ = it.prev_; current_ = it.current_; next_ = it.next_; } // +--------------------------------------------------------------------------- // + Clist<T>::const_iterator::~const_iterator() - Destruktor // + , 20.12.2007 // + wie bei der Klasse iterator Destruktor // +--------------------------------------------------------------------------- template <typename T> Clist<T>::const_iterator::~const_iterator() throw(){ prev_ = 0; current_ = 0; next_ = 0; } // +--------------------------------------------------------------------------- // + Clist<T>::const_iterator::operator++() - Inkrement, Präfix // + Keine Plausibilitätsprüfung! Spezielle Behandlung der Fälle "vor" und // + "nach" der Liste. // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> typename Clist<T>::const_iterator& Clist<T>::const_iterator::operator++() throw(){ if( current_ ){ prev_ = current_; current_ = next_; if( current_ ) next_ = current_->next_ ; else next_ = 0; } else if( next_ ){ // vor dem Anfang prev_ = 0; current_ = next_; if( current_ )next_ = current_->next_; else next_ = 0; } return *this; } // +--------------------------------------------------------------------------- // + Clist<T>::const_iterator::operator++(int) - Inkrement, Postfix // + Keine Plausibilitätsprüfung! // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> typename Clist<T>::const_iterator Clist<T>::const_iterator::operator++(int) throw(){ //die Werte des alten Operanden "sichern" iterator It; It.prev_ = prev_; It.current_ = current_; It.next_ = next_; ++( *this ); return It; } // +--------------------------------------------------------------------------- // + Clist<T>::const_iterator::operator--() - Dekrement, Präfix // + Keine Plausibilitätsprüfung! Spezielle Behandlung der Fälle "vor" und // + "nach" der Liste. // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> typename Clist<T>::const_iterator& Clist<T>::const_iterator::operator--() throw(){ if( current_ ){ next_ = current_; current_ = prev_; if( current_ ) prev_ = current_->prev_ ; else prev_ = 0; } else if( prev_ ){ next_ = 0; current_ = prev_; if( current_ ) prev_ = current_->prev_; else prev_ = 0; } return *this; } // +--------------------------------------------------------------------------- // + Clist<T>::const_iterator::operator--(int) - Dekrement, Postfix // + Keine Plausibilitätsprüfung! // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> typename Clist<T>::const_iterator Clist<T>::const_iterator::operator--(int) throw(){ //die Werte des alten Operanden "sichern" iterator It; It.prev_ = prev_; It.current_ = current_; It.next_ = next_; --( *this ); return It; } // +--------------------------------------------------------------------------- // + Clist<T>::const_iterator::operator=(const_iterator const&) // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> typename Clist<T>::const_iterator& Clist<T>::const_iterator:: operator=(const_iterator const&it)throw(){ prev_ = it.prev_; current_ = it.current_; next_ = it.next_; return (*this); } // +--------------------------------------------------------------------------- // + Clist<T>::const_iterator::operator==(const_iterator const&) - nur // + const_iteratoren zum selben Container können gleich sein! // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> bool Clist<T>::const_iterator:: operator==(const_iterator const & it ) const throw(){ return prev_==it.prev_ && current_==it.current_ && next_==it.next_; } // +--------------------------------------------------------------------------- // + Clist<T>::const_iterator::operator!=(const_iterator const&) // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> bool Clist<T>::const_iterator:: operator!=(const_iterator const & it) const throw(){ return !( *this == it ); } // +--------------------------------------------------------------------------- // + Clist<T>::const_iterator::operator*() - Zugriff auf das Element, auf // + das der aktuelle const_Iterator "verweist". // + Die Plausibilitätskontrolle ist bei den gängigen STL Implementierungen // + nicht vorhanden wegen der Laufzeitverschlechterung. // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> const T& Clist<T>::const_iterator::operator*()const { if( ((!current_) && (!next_)) || ((!prev_) && (!current_)) ) throw out_of_range("*op bad iterator"); // (!current_) && (!next_) -> am hinteren Ende der Liste? // (!prev_) && (!current_) -> am vorderen Ende der Liste? return current_->value_; } // +--------------------------------------------------------------------------- // + Clist<T>::const_iterator::operator->() - Zugriff auf das Elemente, // + auf das der aktuelle const_Iterator "verweist". // + Die Plausibilitätskontrolle ist bei den gängigen STL Implementierungen // + nicht vorhanden wegen der Laufzeitverschlechterung. // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> const T* Clist<T>::const_iterator::operator->() const { if( ((!current_) && (!next_)) || ((!prev_) && (!current_)) ) throw out_of_range("->op bad iterator"); //Erklärung siehe operator*() //(!current_) && (!next_) -> am hinteren Ende der Liste? //(!prev_) && (!current_) -> am vorderen Ende der Liste? return &(current_->value_); } // +--------------------------------------------------------------------------- // + Implementierung von Klasse ClistElem // +--------------------------------------------------------------------------- // +--------------------------------------------------------------------------- // + ClistElem<T>::ClistElem(T const & =T()) - der einzige Konstruktor; // + definiert den Standardkonstruktor mit, da der einzige Parameter // + wegen der Vorbesetzung auch fehlen kann. // + , 20.12.2007 // +--------------------------------------------------------------------------- template <typename T> ClistElem<T>::ClistElem(T const &s) : prev_(0), next_(0), value_(s) {} // +--------------------------------------------------------------------------- // + ClistElem<T>::link_(ClistElem *, bool) - ein neues Element p beim // + aktuellen Listenelement einfügen. // + // +--------------------------------------------------------------------------- template <typename T> void ClistElem<T>::link_(ClistElem *elem, bool append) throw() { if (!elem) return; if (append) { // elem nach dem aktuellen einhängen elem->prev_ = this; elem->next_ = next_; if (next_) next_->prev_ = elem; next_ = elem; } else { // ... vor dem aktuellen elem->next_ = this; elem->prev_ = prev_; if (prev_) prev_->next_ = elem; prev_ = elem; } } // +--------------------------------------------------------------------------- // + ClistElem<T>::link_(ClistElem *first, ClistElem *last, bool append) - // + beim aktuellen Element eine ganze bereits verkettete Liste einfügen // + ("merge"): [first,last] - also inklusive last! // + // +--------------------------------------------------------------------------- template <typename T> void ClistElem<T>::link_(ClistElem *first, ClistElem *last, bool append) throw() { if (!first || !last) return; if (append) { // nach dem aktuellen Element einhängen first->prev_ = this; last->next_ = next_; if (next_) next_->prev_ = last; next_ = first; } else { // vor dem aktuellen Element einhängen last->next_ = this; first->prev_ = prev_; if (prev_) prev_->next_ = first; prev_ = last; } } // +--------------------------------------------------------------------------- // + ClistElem<T>::unlink_() - das aktuelle Element aus der Liste aushängen. // + // +--------------------------------------------------------------------------- template <typename T> void ClistElem<T>::unlink_() throw() { if (prev_) prev_->next_ = next_; if (next_) next_->prev_ = prev_; } // +--------------------------------------------------------------------------- // + ClistElem<T>::unlink_(ClistElem *last) - den Teil der Liste vom // + aktuellen Element bis einschließlich(!) last aushängen ("splice") // + [this,last] - also inklusive last! // + // +--------------------------------------------------------------------------- template <typename T> void ClistElem<T>::unlink_(ClistElem *last) throw() { if (!last) return; if (prev_) prev_->next_ = last->next_; if (last->next_) last->next_->prev_ = prev_; } template<typename T> void Clist<T>::resize(size_type sz, T c ){ } template<typename T> void Clist<T>::reverse(){ /* if(!head_) return; while( head_ != tail_ ){ // ---> endlose Schleife, falls die Liste nicht std::swap(head_-> value_ , tail_ -> value_); // ---> leer ist!!! //head_ ++; } */ ClistElem<T> *p(head_); ClistElem<T> *q(tail_); for( ; p !=q ; p=p->nxt_,--q) std::swap(p->value, q->value); } /* for( ;head_ != tail_; head_=head_->next_) head_ = tail_; */ } // namespace swe3 // #endif // // +--------------------------------------------------------------------------- // + Liste der Änderungen // + Datenelement Datum AutorIn Beschreibung // +--------------------------------------------------------------------------- // + Modul 20.12.2007 erste Version // + 24.12.2007 zweite Version // + 04.12.2007 letzte Version // + // // Ende der Datei
-
Ich muss jetzt oben stehende Klasse-Clist mit anderen Funktionen wie resize,rend usw. erweitern.
-
strong schrieb:
Ich muss jetzt oben stehende Klasse-Clist mit anderen Funktionen wie resize,rend usw. erweitern.
Woran haperts denn genau?
-
Einer von diesen Funktionen wird Klausur-Aufgabe. Wir müssen Implementierungen selbst schreiben. Der will nicht, dass man einfach die Funktionen aus der Bibliothek nutzt.
-
Hier Lösungen oder Lösungsskizzen zu zeigen, wäre so etwas wie Hausaufgaben machen. Der bisherige Aufbau ist nicht ganz unbrauchbar, aber es haben sich auch einige Fehler (die ich hier nicht aufzählen will, das wäre nach der Klausur denkbar) eingeschlichen und es wird an einigen Stellen - wahrscheinlich aus Unwissenheit - ohne Not vom Verhalten von std::list abgewichen. Der Verzicht auf einen Allokator gehört sicherlich nicht dazu, aber logischerweise führt das natürlich dazu, dass get_allocator überflüssig wird. max_size ist eher uninteressant, wenn man ohne Allokatoren arbeitet. Gleiches gilt dann entsprechend für rbegin,rend.
Was am meisten auffällt, ist, dass offenbar das Wesen - oder die spezielle Eigenheit - doppelt verketteter Listen nicht erkannt wurde: im Gegensatz zu Container wie vector oder deque kann man (im Prinzip - wenn man auf konstante Laufzeit von size() verzichtet, was erlaubt ist) alle interessanten Listenoperationen ausschließlich über Iteratoren implementieren, ohne jedesmal das konkrete Containerobjekt als solches anfassen zu müssen. Oder möglicherweise ist das auch ein fehlendes Verständnis dafür, was ein Iterator ist - jedenfalls ist dessen Implementierung etwas seltsam.Ein paar Kleinigkeiten, die nichts direkt mit dem Problem zu tun haben, kann ich anmerken:
So etwas wie Selbstzuweisung gibt es im Copy-ctor nicht, eine entsprechende Prüfung ist dort fehl am Platz (und ein exceptionsicherer Zuweisungsoperator bedarf einer solchen Prüfung normalerweise auch nicht). Zudem sollten Funktionen durchlässig für Exceptions sein: wenn eine Funktion fehlschlägt, weil zum Beispiel das Kopieren eines Elements fehlschlägt, sollte diese Exception - nach den entsprechenden Aufräumaktionen - unverändert weitergeworfen werden. Dem Aufrufer anzuzeigen, welche Funktion fehlgeschlagen ist, ist schließlich sinnlos: das weis der Aufrufer sowieso - nicht aber welche konkrete elementare Funktion nicht durchgeführt werden konnte. new liefert niemals 0 zurück.
Destruktoren sollten (im Zusammenhang mit der Standardbibliothek) niemals Exceptions auslösen. Es ist praktisch unmöglich, excptionsicher zu progammieren, wenn diese Regel nicht eingehalten wird, das muss daher dann auch nicht behandelt werden. der Vollständigkeit halber kannst du dem Destruktor auch noch die entsprechende leere Exceptionspezifikation verpassen.
Die Iterator-Operatoren * und -> sollten const sein.
Der value_type eines const_iterators bleibt ohne zusätzliches const (wird nicht vorgeschrieben - aber Analogie zu iterator_traits<T*>)Die einzig wirklich interessante und sehr wichtige Operation mit Listen ist splice - damit lassen sich andere Funktionen leichter implementieren: indem swaps durch splice durchgeführt werden, entfallen potentielle Quellen für das Werfen von Exceptions, und zum Einhalten der Komplexitätsgarantien ist es ebenfalls unverzichtbar.