8. Реализация на свързани списъци

План:
Реализация на свързани списъци - класове, итератори,  операции

* Ще реализираме свързан списък с елементи - низове.

list
* Всеки връх на списъка съдържа низ и два указателя - адреси на предишен и следващ връх на свързания списък.

class Node {
public:
Node(string s);
private:
string data; // данна (низ)
Node* previous; // адрес на предишния връх
Node* next; // адрес на следващия връх
friend class
List;
friend class Iterator;
};

* Ключовата дума friend означава, че класът Node дава на член-функциите на класовете List и Iterator достъп до частните си членове.
* Указателят previous на първия елемент на свързния списък има стойност NULL.
* Указателят next на последния елемент на свързния списък има стойност NULL.


* Свързан списък се задава, като се посочи адресът на първия му елемент.
* Всеки обект от класа List ще съдържа адресите на първия (задължително) и последния (за удобство) елементи на свързания списък.
class List {
public:
List();
void push_back(string s);
void insert(Iterator pos, string s);
Iterator erase(Iterator pos);
Iterator begin();
Iterator end();
private:
Node* first; // адрес на първия елемент (връх, възел)
Node* last; // адрес на последния елемент (връх, възел)
};

* Когатo свързният списък е празен, двата указателя first и last имат стойност NULL.


* Итераторът задава позиция (на връх) в свързания списък - указател position.

class Iterator {
public:
Iterator();
string get() const; /* use instead of operator * of the STL iterator */
void next(); /* use instead of operator ++ of the STL iterator */
void previous(); /* use instead of operator -- of the STL iterator */
bool equals(Iterator b) const; /* use instead of operator == of the STL iterator */
private:
Node* position; // адрес на връх в свързания списък
Node* last; // адрес на последния елемент на свързания списък
friend class List;
};

* Когато итераторът задава позиция "след последния елемент", стойността на  position е NULL


** Функциите begin и end от класа List  връщат итератори:

Iterator List::begin() 
{
Iterator iter;
iter.position = first;
iter.last = last;
return iter;
}

Iterator List::end()
{
Iterator iter;
iter.position = NULL;
iter.last = last;
return iter;
}

** Функцията next от класа Iterator премества итератора на следващия елемент на списъка:

void Iterator::next()
{
assert(position != NULL)
position = position->next;
}

* Подобна е функцията previous:

void Iterator::previous()
{
if
(position == NULL) position = last;
else position = position->previous;
assert(position != NULL);
}

** Реализация на функция push_back от класа List:

void List::push_back(string s)
{
Node* newnode = new Node(s);
if (last == NULL) /* list is empty */
{
first = newnode;
last = newnode;
}
else /* list is nonempty */
{
newnode->previous = last;
last->next = newnode;
last = newnode;
}
}

** Функцията insert променя данни на предишния (next) и следващия (previous) върхове - важен е редът на присвояванията.

* Специален случай за празен списък:

if (iter.position == NULL)
{
push_back(s);
return;
}

* Създаваме указатели към двата съседни върха:

Node* after = iter.position;
Node* before = after->previous;

* Инициализираме адресите на новия връх:

newnode->previous = before; // (1)
newnode->next = after; // (2)

* Променяме указателите за следващ и предишен на съседните върхове:

after->previous = newnode;  // (3)
if (before == NULL) /* insert at beginning */
first = newnode;
else
before->next = newnode; // (4)

** Реализация на функцията за изтриване на връх.

* Дефинираме указатели за трите върха:

Node* remove = iter.position;
Node* before = remove->previous;
Node* after = remove->next;

* Променяме предишния връх - "откачваме" върха, който ще трием, и "закачваме" следващия връх.

if (remove == first) first = after;
else before->next = after;

* Аналогично и за следвашия връх:

if (remove == last) last = before;
else after->previous = before;

* Накрая изтриваме върха.

delete remove;

* Ето и целия текст на програмата:

// list2.cpp
 
#include <string>
#include <iostream>
#include <cassert>
using namespace std;

/* декларации на класовете List и Iterator за да могат да бъдат използвани при дефиниране на List*/
class List;
class Iterator;
 
/* елемент на свързания списък */
class Node {
public:
   Node(string);
private:
   string data;
   Node* previous;
   Node* next;
/* член-функциите на класовете List и Iterator имат достъп до частните членове на класа Node */
   friend class List;
   friend class Iterator;
};

class List {
public:
   List();
   void push_back(string);
   void insert(Iterator, string);
   void erase(Iterator);
   Iterator begin(); /* начало на свързания списък */
   Iterator end();   /* край на свързания списък */
private:
   Node* first;  /* първи елемент на свързания списък */
   Node* last;   /* последен елемент на свързания списък */
};

class Iterator {
public:
   Iterator();
   string get() const; /* реализира операция * за итератори */
   void next();        /* реализира операция ++ за итератори */
   void previous();    /* реализира операция -- за итератори */
   bool not_equal(Iterator) const; /* реализира операция != */
private:
   Node* position; /* текущ елемент на свързания списък */
   Node* last;     /* последен елемент на свързания списък */
 
/* член-функциите на класа List имат достъп до частните членове на Iterator */
   friend class List;
};

Node::Node(string s)
/* ПОЛУЧАВА: s - данната, която ще се съхранява в този елемент */
{
   data = s; 
   previous = NULL;  next = NULL;
}

List::List()
/* ЦЕЛ: конструира празен свързан списък */
{
   first = NULL; last = NULL;
}

void List::push_back(string s)
/* ЦЕЛ: добавя елемент към свързан спесък
   ПОЛУЧАВА: s - данната, която ще се добави
*/
{
  Node* newnode = new Node(s);

  if (last == NULL)            /* празен свързан списък */
  {
     first =
newnode; last = newnode;
  }

  else
  {
    newnode
->previous = last;

    last->next = newnode;
    last = newnode;
  }
}

void List::insert(Iterator iter, string s)
/* ЦЕЛ: вмъква елемент в свързан списък
   ПОЛУЧАВА: iter - позицията, преди която да се вмъкне
             s - данната, която ще се вмъкне
*/
{
  if (iter.position == NULL) /* вмъкване в края */

  {
     push_back(s);  return; 
  }

  Node* after = iter.position;
  Node* before = after->previous;
  Node* newnode = new Node(s);
 
  newnode->previous = before;
  newnode->next = after;
  after->previous = newnode;
 
  if (before == NULL) first = newnode; /* вмъкване в началото */
  else before->next = newnode;
}

void List::erase(Iterator iter)
/* ЦЕЛ: отстранява елемент от свързан списък
   ПОЛУЧАВА: iter - позицията на елемента, който ще се отстрани
*/
{
  assert(iter.position != NULL);
 
  Node* remove = iter.position;
  Node* before = remove->previous;
  Node* after = remove->next;
 
  if (remove == first) first = after;/* изтриване на първия елемент */
  else          before->next = after;
 
  if (remove == last)  last = before;/* изтриване на последния елемент */
  else      after->previous = before;
 
  iter.position = after;
  delete remove;
}

Iterator List::begin()
/* ВРЪЩА: итератор, сочещ към началната позиция на свързан списък */
{
  Iterator iter;

  iter.position = first;
  iter.last = last;
  return iter;
}

Iterator List::end()
/* ВРЪЩА: итератор, сочещ след края на списъка (NULL) */
{
  Iterator iter;

  iter.position = NULL;
  iter.last = last;
  return iter;
}

Iterator::Iterator()

  position = NULL;   last = NULL; 
}

string Iterator::get() const
/* ВРЪЩА: данната на елемента, който сочи итератора */
{
  assert(position != NULL);

  return position->data;
}

void Iterator::next()
/* ЦЕЛ: да премести итератора на следващия елемент от списъка */
{
  assert(position != NULL);

  position = position->next;
}

void Iterator::previous()
/* ЦЕЛ: да премести итератора на предишния елемент от списъка */
{
  if (position == NULL)  position = last;

  else                   position = position->previous;
  assert(position != NULL);
}

bool Iterator::not_equal(Iterator b) const
/* ЦЕЛ: сравнява два итератора
   ПОЛУЧАВА: b - вторият итератор за сравнението
   ВРЪЩА: true ако този итератор и b не са равни
*/
{
  return position != b.position;
}

int main()
{
  List staff; 
/* обект от класа List */
 
  staff.push_back("Cracker, Carl");
  staff.push_back("Hacker, Harry");
  staff.push_back("Lam, Larry");
  staff.push_back("Sandman, Susan");

  Iterator pos;
/* итератор на списък */

/* добавя елемент на четвърто място */
  pos = staff.begin();
  pos.next();  
  pos.next();  
  pos.next();

  staff.insert(pos, "Reindeer, Rudolf");

/* отстранява втория елемент */
  pos = staff.begin();
  pos.next();
  staff.erase(pos);

/* отпечатва свързания списък */
  for (pos = staff.begin(); pos.not_equal(staff.end());
       pos.next()) cout << pos.get() << "\n";
 /* извежда данната на текущата позиция */

  return 0;
}

int main()

   list<string> staff;

/* шаблон за списък */

   staff.push_back("Cracker, Carl");
   staff.push_back("Hacker, Harry");
   staff.push_back("Lam, Larry");
   staff.push_back("Sandman, Susan");

   list<string>::iterator pos;
/* итератор на списък */

/* добавя елемент на четвърто място */
   pos = staff.begin();
   pos++;
   pos++;
   pos++;
   staff.insert(pos, "Reindeer, Rudolf");

/* отстранява втория елемент */
   pos = staff.begin();
   pos++;
   staff.erase(pos);

/* обхождане на списък */
   for (pos = staff.begin(); pos != staff.end(); pos++)
      cout << *pos << "\n"; 
/* извежда данната на текущата позиция */
 
   return 0;
}

Резултат от работата на програмата:

Cracker, Carl
Lam, Larry
Reindeer, Rudolf
Sandman, Susan

Начално състояние на списъка:

Cracker, Carl
NULL
->
Hacker, Harry
<-
->
Lam, Larry
<-
->
Sandman, Susan
<-
NULL

След добавяне на елемент на четвърто място:

Cracker, Carl
NULL
->

Hacker, Harry
<-
->

Lam, Larry
<-
->

Reindeer, Rudolf
<-
->

Sandman, Susan
<-
NULL


След отстраняване на втория елемент:
Cracker, Carl
NULL
->
Lam, Larry
<-
->
Reindeer, Rudolf
<-
->
Sandman, Susan
<-
NULL