Односвязный список - это совокупность нескольких объектов, каждый из которых представляет собой элемент списка, состоящий из двух частей. Первая часть элемента - значение, которое он хранит, вторая - информация о следующем элементе списка.
Характер информации о следующем элементе зависит от того, где конкретно хранится список. Например, если это оперативная память, то информация будет представлять собой адрес следующего элемента, если файл - позицию следующего элемента в файле. Мы с Вами будем рассматривать реализацию списка хранящегося в оперативной памяти, однако, при желании, вы сможете создать собственный код для хранения списка в файле. Итак, приступим:
Каждый элемент списка мы представим программно с помощью структуры, которая состоит из двух составляющих:
1.Одно или несколько полей, в которых будет содержаться основная информация, предназначенная для хранения.
2. Поле, содержащее указатель на следующий элемент списка.
Отдельные объекты подобной структуры мы далее будем называть узлами, связывая их между собой с помощью полей, содержащих указатели на следующий элемент.
//узел списка
struct node
{
// Информационная часть узла
int value;
// Указатель на следующий узел списка
node *next;
};
После создания структуры, нам необходимо инкапсулировать её объекты в некий класс, что позволит управлять списком, как цельной конструкцией. В классе будет содержаться два указателя (на хвост, или начало списка и голову, или конец списка), а так же набор функции для работы со списком.
//голова node *phead;
//хвост node *ptail;
В целом, полученный список можно представить так:
Итак, основные моменты создания списка, мы рассмотрели, переходим непосредственно к его формированию.
Формирование списка. Отведем место для указателей в статической памяти.
node *phead; node *ptail;
Зарезервируем место для динамического объекта.
phead=new node;
Присвоим значение переменной ptail, и поместим в информационное поле значение элемента.
ptail = phead; ptail->value = "значение1";
Поместим в поле узла адрес еще одного - нового динамического объекта.
ptail->next = new node;
Переменная ptail должна содержать адрес последнего добавленного элемента, т. к. он добавлен в конец.
ptail = ptail->next;
Если требуется завершить построение списка, то в поле указателя последнего элемента нужно поместить NULL.
ptail->next = NULL; ptail->value = "значение2";
В результате построен линейный односвязный список, содержащий два узла.
Вставка узла в определенное заданное место списка. Здесь и далее, мы не будем приводить фрагменты кода, так как они являются крупными. Позже мы с вами просто рассмотрим пример реализации односвязного списка целиком. А, сейчас, разберем операции над списком с помощью иллюстраций. Выделить память под новый узел. Записать в новый узел значение. Записать в указатель на следующий узел адрес узла, который должен располагаться после нового узла. Заменить в узле, который будет располагаться перед новым узлом, записанный адрес на адрес нового узла.
Удаление узла из списка. Записать адрес узла, следующего за удаляемым узлом, в указатель на следующий узел в узле, предшествующем удаляемому. Удалить узел, предназначенный для удаления.
#include <iostream>
using namespace std;
struct Element
{
// Данные
char data;
// Адрес следующего элемента списка
Element * Next;
};
// Односвязный список
class List
{
// Адрес головного элемента списка
Element * Head;
// Адрес головного элемента списка
Element * Tail;
// Количество элементов списка
int Count;
public:
// Конструктор
List();
// Деструктор
~List();
// Добавление элемента в список
// (Новый элемент становится последним)
void Add(char data);
// Удаление элемента списка
// (Удаляется головной элемент)
void Del();
// Удаление всего списка
void DelAll();
// Распечатка содержимого списка
// (Распечатка начинается с головного элемента)
void Print();
// Получение количества элементов, находящихся в списке
int GetCount();
};
List::List()
{
// Изначально список пуст
Head = Tail = NULL;
Count = 0;
}
List::~List()
{
// Вызов функции удаления
DelAll();
}
int List::GetCount()
{
// Возвращаем количество элементов
return Count;
}
void List::Add(char data)
{
// создание нового элемента
Element * temp = new Element;
// заполнение данными
temp->data = data;
// следующий элемент отсутствует
temp->Next = NULL;
// новый элемент становится последним элементом списка
// если он не первый добавленный
if(Head!=NULL){
Tail->Next=temp;
Tail = temp;
}
// новый элемент становится единственным
// если он первый добавленный
else{
Head=Tail=temp;
}
}
void List::Del()
{
// запоминаем адрес головного элемента
Element * temp = Head;
// перебрасываем голову на следующий элемент
Head = Head->Next;
// удаляем бывший головной элемент
delete temp;
}
void List::DelAll()
{
// Пока еще есть элементы
while(Head != 0)
// Удаляем элементы по одному
Del();
}
void List::Print()
{
// запоминаем адрес головного элемента
Element * temp = Head;
// Пока еще есть элементы
while(temp != 0)
{
// Выводим данные
cout << temp->data << " ";
// Переходим на следующий элемент
temp = temp->Next;
}
cout << "\n\n";
}
// Тестовый пример
void main()
{
// Создаем объект класса List
List lst;
// Тестовая строка
char s[] = "Hello, World !!!\n";
// Выводим строку
cout << s << "\n\n";
// Определяем длину строки
int len = strlen(s);
// Загоняем строку в список
for(int i = 0; i < len; i++)
lst.Add(s[i]);
// Распечатываем содержимое списка
lst.Print();
// Удаляем три элемента списка
lst.Del();
lst.Del();
lst.Del();
//Распечатываем содержимое списка
lst.Print();
}