<?xml version='1.0' encoding="utf-8"?>
      <rss version='2.0'>
      <channel>
      <title>Форум на Исходниках.RU</title>
      <link>https://forum.sources.ru</link>
      <description>Форум на Исходниках.RU</description>
      <generator>Форум на Исходниках.RU</generator>
  	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=69615&amp;view=findpost&amp;p=486369</guid>
        <pubDate>Mon, 18 Oct 2004 18:11:15 +0000</pubDate>
        <title>Связанные списки</title>
        <link>https://forum.sources.ru/index.php?showtopic=69615&amp;view=findpost&amp;p=486369</link>
        <description><![CDATA[Some1: <div class='tag-align-center'><span class='tag-size' data-value='14' style='font-size:14pt;'><span class="tag-color tag-color-named" data-value="blue" style="color: blue"><strong class='tag-b'>Связанные списки</strong></span></span></div><br>
Все начинающие программисты рано или поздно сталкиваются с проблемами, которые решить можно только при помощи связанных списков. Но о их существовании эти программисты не знают, и поэтому часами, а то и сутками ломают себе голову, как же им выкрутиться. В этом топике я подробно опишу то, когда нам нужны связанные списки, и как ими пользоваться.<br>
<strong class='tag-b'>Прежде чем прочесть эту тему вам следует знать (ну, или хотя бы иметь представление) что такое:</strong><ul class="tag-list"><li><a class='tag-url' href='http://pascaler.wsnet.ru/arrays/arrays.php' target='_blank'>Массивы</a>: одномерные(их ещё называют векторами) и двумерные (их еще называют матрицами)</li><li><a class='tag-url' href='http://forum.sources.ru/index.php?showtopic=50681' target='_blank'>Указатели (Pointers)</a>. Важно знать про Типизированные указатели.<br>
Динамическая память (Dynamic memory или Heap Memory)</li><li>Тип данных - <a class='tag-url' href='http://forum.sources.ru/index.php?showtopic=40431' target='_blank'>Запись (Record)</a></li></ul><br>
<strong class='tag-b'>Рассмотрим реальный случай из жизни:</strong><br>
<br>
Допустим вам нужно написать простой текстовый редактор, который бы загружал текстовый файл в память, и потом позволял бы изменять текст, загруженный в память.<br>
<br>
И вы решили организовать это так:<br>
<br>
Завести большой массив из строк. Каждая строка с 1 по N-ную в этом массиве будет содержать соответствующую строку из файла. И все бы хорошо, и можно было бы такой массив сделать, но как же быть.. Ведь мы в начале не знаем, сколько строк будет в файле, и не знаем, сколько элементов объявить в массиве.<br>
<br>
Как обычно новички поступают в таком случае? Они создают массив по принципу &quot;ШОБ ХВАТИЛО&quot; скажем из 500 элементов:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">var dat: array[1 .. 500] of string[80]</div></ol></div></div></div></div><script>preloadCodeButtons('1');</script>, и таким образом получается, что наша программа сможет редактировать файлы из пятисот строк. Но, скажу я вам, это ламерский способ&#33; %) Настоящий программист никогда не позволит себе такой вольности: выделять заранее оговоренное количество строк, и тем самым ограничивать пользователя. Настоящий программист непременно воспользуется связанным списком.<br>
<br>
Связанный список представляет собой подобие массива. Но этот массив объявлять не приходится. Нет одной переменной, которая бы олицетворяла весь массив, и нет у такого &quot;массива&quot; названия. Но есть его подобие. А именно: <em class='tag-i'>Каждый элемент связанного списка на самом деле - независимый участок памяти. Каждый элемент сам по себе. Но они все связаны. Все эти кусочки памяти связаны друг меж другом.</em><br>
<br>
Давайте рассмотрим такую аналогию: Представьте себе толпу людей. Пусть это будет куча элементов с данными в памяти. В толпе людей все люди стоят перемешано, как и элементы в памяти. Один там, другой тут ... А теперь представьте себе, что каждый человек указывает пальцем на какого либо другого человека в этой толпе. Тогда Я могу сказать, что эти люди образуют друг между другом связь.<br>
<br>
Представьте себе: один человек в толпе указывает на другого. Тот в свою очередь указывает на еще кого-то, тот еще на кого-то, и так до какого либо человека, который ни на кого не указывает. Вот точно так же в памяти устроены связанные списки. Каждый элемент в памяти кроме своего значения еще &quot;знает&quot;, где в памяти находится элемент, следующий за ним. А самый последний элемент в последовательности &quot;знает&quot;, что за ним никого нет.<br>
<br>
Теперь на секундочку допустим, что все люди знают по одной строке... ну ... стиха &quot;Буревестник&quot; %) Ну там (буря мглою небо кроет... бла-бла-бла). Но только по одной. Так вот тот человек, который знает первую строку стиха указывает пальцем на человека, который знает вторую строку. Тот в свою очередь указывает на человека, который знает 3 строку. И так до человека, который знает самую последнюю ... как ее там &quot;Пусть сильнее грянет буря&#33;.. &quot;. А этот самый последний уже не указывает ни на кого, давая нам понять, что цепочка людей закончилась.<br>
<br>
Так вот точно так же работают связанные списки.<br>
<br>
Вернемся к нашей задаче о строках в файле.<br>
<br>
Когда у нас есть связанный список, то в первом элементе этого списка нужно поместить первую строку файла, и так-же указать им на второй, чтобы было понятно, где находится следующая строка. Во втором элементе - вторая строка файла, и информация о том, где находится третий элемент. И так далее. Последний элемент не указывает ни на что. Осмыслите как следует и переварите эту информацию, потому что я дальше покажу, как реализуется такой связанный список на Pascal&#39;е.<br>
<br>
Каждый элемент связанного списка принято называть нодой (Node).<br>
<br>
На Паскале каждый элемент мы создаем динамически, и размещаем в динамической памяти ( а я ведь говорил, что нужно знать о динамической памяти :D ). Каждый элемент списка мы описываем как тип данных Record, в котором два поля - значение самого элемента (ну там число, строка или что угодно) и указатель, где в памяти находится следующий после него элемент. Указатель этот должен быть (для удобства) типизированным. Определим два новых типа:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">type</div><div class="code_line">&nbsp;&nbsp;pNode=^TNode; {Типизированный указатель - указатель на данные типа TNode}</div><div class="code_line">&nbsp;&nbsp;TNode=record</div><div class="code_line">&nbsp;&nbsp; &nbsp;Value:/тип данных/; {значение элемента}</div><div class="code_line">&nbsp;&nbsp; &nbsp;Next:PNode; {Указатель на следующий элемент}</div><div class="code_line">&nbsp;&nbsp;end;</div></ol></div></div></div></div><br>
Надеюсь вы понимаете, что это только описание типов данных. Самих данных на самом деле еще нет.<br>
Так вот. Теперь о том что я говорил - а я говорил, что связанный список нельзя описать как массив данных, одной переменной. Зато можно в одной из переменных содержать адрес, где будет находиться самый первый элемент последовательности (ну списка, список еще называют последовательностью). И тогда, зная адрес первого элемента последовательности, можно найти, где находится второй элемент, и потом где находится 3 элемент, и так далее.<br>
Вот пример:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">... объявление типов (Смотри выше)</div><div class="code_line">var</div><div class="code_line">&nbsp;&nbsp;First:pnode; {Указатель на место в памяти, где находится первый элемент последовательности}</div></ol></div></div></div></div>Тут следует сказать, что последний элемент не должен ни на что не указывать. Как это делается на Паскале? Так как указываем на следующий элемент мы при помощи указателей, то указатель, который ни на что не указывает всегда равен NIL. И следовательно если в элементе поле Next=NIL, то это последний элемент в цепочке.<br>
Ну хорошо. Примерно уяснили, как следует описывать элементы списка. А как его вообще создать?<br>
Для того чтобы создать связанный список мы должны в памяти выделять память под динамические ячейки, и для каждого элемента списка настроить значения параметра Next так, чтобы там действительно адрес следующей ячейки, либо же значение NIL (пусто) если это последняя ячейка в последовательности.<br>
Вот простейшая реализация такого связанного списка:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">type</div><div class="code_line">&nbsp;&nbsp;pNode=^TNode; {Типизированный указатель - указатель на данные типа TNode}</div><div class="code_line">&nbsp;&nbsp;TNode=record</div><div class="code_line">&nbsp;&nbsp; &nbsp;Value:integer; {значение элемента}</div><div class="code_line">&nbsp;&nbsp; &nbsp;Next:PNode; {Указатель на следующий элемент}</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">var</div><div class="code_line">&nbsp;&nbsp;First:pnode; </div><div class="code_line">&nbsp;&nbsp;Temp:pnode; {временный указатель на ячейку. Понадобится для построения связанного списка}</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;{Создадим список из 4 элементов с разными числами}</div><div class="code_line">&nbsp;&nbsp;New(Temp); {Создали в памяти новый элемент. На него указывает указатель Temp}</div><div class="code_line">&nbsp;&nbsp;First:=Temp; {Это и будет первый элемент последовательности.</div><div class="code_line">&nbsp;Поэтому в указатель First мы занесем его адрес}</div><div class="code_line">&nbsp;&nbsp;Temp^.Value:=10; {Задаем значение для 1 элемента}</div><div class="code_line">&nbsp;&nbsp;New(Temp^.Next); {Создали новый (2) элемент в памяти. На него указывает указатель Temp^.Next}</div><div class="code_line">&nbsp;&nbsp;Temp:=Temp^.Next; {Теперь Temp - это указатель на новый (2) элемент.</div><div class="code_line">&nbsp;Причём в предыдущем (1) элементе Next указывает именно на него, как нам и нужно}</div><div class="code_line">&nbsp;&nbsp;Temp^.Value:=20; &nbsp;{Задаем значение для 2 элемента}</div><div class="code_line">&nbsp;&nbsp;New(Temp^.Next); {Создали новый (3) элемент в памяти. На него указывает указатель Temp^.Next}</div><div class="code_line">&nbsp;&nbsp;Temp:=Temp^.Next; {Теперь Temp - это указатель на новый (3) элемент.</div><div class="code_line">&nbsp;Причём в предыдущем (2) элементе Next указывает именно на него, как нам и нужно}</div><div class="code_line">&nbsp;&nbsp;Temp^.Value:=30; &nbsp;{Задаем значение для 3 элемента}</div><div class="code_line">&nbsp;&nbsp;New(Temp^.Next); {Создали новый элемент в памяти. На него указывает указатель Temp^.Next}</div><div class="code_line">&nbsp;&nbsp;Temp:=Temp^.Next; {Теперь Temp - это указатель на новый (4) элемент.</div><div class="code_line">&nbsp;Причём в предыдущем (3) элементе Next указывает именно на него, как нам и нужно}</div><div class="code_line">&nbsp;&nbsp;Temp^.Value:=40; &nbsp;{Задаем значение для 4 элемента}</div><div class="code_line">&nbsp;&nbsp;Temp^.Next:=NIL; {Последний (4) элемент не должен указывать ни на какой.</div><div class="code_line">&nbsp;Поэтому у него Next должно быть NIL}</div><div class="code_line">end.</div></ol></div></div></div></div><br>
Таким вот образом мы вручную создали связанный список из 4 элементов. Фактически его можно использовать как массив.<br>
Но для доступа к определенному элементу уже нельзя будет использовать его порядковый номер. Нужно будет последовательно начиная с элемента, на который указывает переменная First искать нужный нам.<br>
Зато такой связанный список может содержать в себе сколько угодно (а точнее на сколько хватит памяти) элементов.<br>
А давай-те ка я это продемонстрирую. Автоматизируем процесс. Позволим пользователю вводить сколько угодно элементов, а потом все их выведем на экран:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">type</div><div class="code_line">&nbsp;&nbsp;pNode=^TNode; {Типизированный указатель - указатель на данные типа TNode}</div><div class="code_line">&nbsp;&nbsp;TNode=record</div><div class="code_line">&nbsp;&nbsp; &nbsp;Value:integer; {значение элемента}</div><div class="code_line">&nbsp;&nbsp; &nbsp;Next:PNode; {Указатель на следующий элемент}</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">var</div><div class="code_line">&nbsp;&nbsp;First:pnode; </div><div class="code_line">&nbsp;&nbsp;Temp:pnode; {временный указатель на ячейку. Понадобится для построения связанного списка}</div><div class="code_line">&nbsp;&nbsp;v:integer;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;First:=nil; {В начале у нас First не указывает ни на что}</div><div class="code_line">&nbsp;&nbsp;repeat</div><div class="code_line">&nbsp;&nbsp; &nbsp;write(&#39;Введите значение нового элемента (0 для выхода):&#39;);</div><div class="code_line">&nbsp;&nbsp; &nbsp;readln(v);</div><div class="code_line">&nbsp;&nbsp; &nbsp;if v=0 then break; {Если ввели 0, то окончим ввод элементов}</div><div class="code_line">&nbsp;&nbsp; &nbsp;if First=NIL then {Если First=NIL, то сейчас мы создадим первый элемент}</div><div class="code_line">&nbsp;&nbsp; &nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;new(Temp); {Создали первый элемент. Его адрес в Temp}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;First:=Temp; {Так как элемент первый, запомним его адрес}</div><div class="code_line">&nbsp;&nbsp; &nbsp;end else {Иначе это уже не первый элемент}</div><div class="code_line">&nbsp;&nbsp; &nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;New(Temp^.Next); {Создаем на основе предыдущего, чтобы сохранилась связь между элементами}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;Temp:=Temp^.Next; {Текущий элемент теперь тот, который мы только что создали.</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; И предыдущий указывает на него}</div><div class="code_line">&nbsp;&nbsp; &nbsp;end;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Temp^.Value:=v; {Зададим значение текущего элемента}</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp;until false; {Бесконечный цикл. Прервется только если пользователь введет 0}</div><div class="code_line">&nbsp;&nbsp;{Всё у нас хорошо. Только вот в последнем элементе параметр Next не определен. Непорядок}</div><div class="code_line">&nbsp;&nbsp;Temp^.Next:=NIL; {Ну вот теперь то лучше}</div><div class="code_line">&nbsp;&nbsp;{Заметьте, что даже если пользователь сразу введет 0, то в переменной First будет NIL,</div><div class="code_line">&nbsp;что значит - пустой список}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;{Теперь выведем наш связанный список. Адрес его первого элемента находится в переменной First,</div><div class="code_line">&nbsp;и это хорошо %)}</div><div class="code_line">&nbsp;&nbsp;Temp:=First; {Укажем переменной Temp на первый элемент последовательности}</div><div class="code_line">&nbsp;&nbsp;while Temp&#60;&#62;NIL do {Пока текущий элемент существует}</div><div class="code_line">&nbsp;&nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp;writeln(Temp^.Value); {Выводим текущий элемент}</div><div class="code_line">&nbsp;&nbsp; &nbsp;Temp:=Temp^.Next; {Переходим к следующему}</div><div class="code_line">&nbsp;&nbsp; &nbsp;{Обратите внимание, что если следующий элемент не существует,</div><div class="code_line">&nbsp;&nbsp; &nbsp; то в Temp попадет значение NIL, и цикл прекратится}</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">end.</div></ol></div></div></div></div><br>
Только что мы рассмотрели принцип создания простого связанного списка. Но я ничего не сказал об удалении. Хотя компилятор Borland Pascal вставляет в код программы автоматически код, который высвобождает всю память, которая была отведена командой New под новые элементы, но все же хорошим тоном считается удалить все элементы из памяти.<br>
Поэтому нам нужно реализовать цикл, подобный тому, когда мы выводили элементы на экран, но при этом мы должны удалять элементы командой Dispose.<br>
Вот так:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp;while First&#60;&#62;NIL do {Пока текущий элемент существует}</div><div class="code_line">&nbsp;&nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp;Temp:=First;</div><div class="code_line">&nbsp;&nbsp; &nbsp;First:=First^.Next; {Переходим к следующему}</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dispose(Temp); {Теперь удаляем элемент, который был}</div><div class="code_line">&nbsp;&nbsp; &nbsp;{Важно не перепутать две предыдущие строчки местами. сначала мы переходим к следующему элементу,</div><div class="code_line">&nbsp;&nbsp; &nbsp; а потом высвобождаем память от уже ненужного элемента}</div><div class="code_line">&nbsp;&nbsp;end;</div></ol></div></div></div></div><br>
<br>
Ну что ж. Основные сведения я уже изложил.<br>
Теперь основные прикладные функции. Их 3: Поиск элемента в списке по значению, Вставка нового элемента, Удаление существующего элемента.<br>
<br>
<strong class='tag-b'><span class='tag-size' data-value='11' style='font-size:11pt;'>Поиск элемента в списке по значению</span></strong><br>
Вернёмся к нашей аналогии с толпой людей. Как бы мы искали в толпе людей, знающих по одной строчке из стиха определенного человека, который знает определенную строчку?<br>
Мы бы подошли к первому , узнали, какую строчку он знает. Если это не та, которая нам нужна, то узнали бы, куда он показывает, и пошли бы к тому человеку. После чего повторили бы действия. И повторяли бы их до тех пор, пока не нашли человека, знающего нужную нам строчку. Так в чем же проблема? реализуем этот принцип на Паскале &#33; %)<br>
...Задание переменных и создание связанного списка в памяти...<br>
...В переменной v находится число, с значением которого мы хотим найти элемент...<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp;Temp:=First;</div><div class="code_line">&nbsp;&nbsp;while Temp&#60;&#62;NIL do {Пока элемент существует}</div><div class="code_line">&nbsp;&nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp;if Temp^.Value=v then break; {Если нашелся элемент с нужным нам значением, то прервем цикл}</div><div class="code_line">&nbsp;&nbsp; &nbsp;Temp:=Temp^.Next; {Переходим к следующему элементу}</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">&nbsp;&nbsp;{По окончании этого цикла указатель Temp будет указывать на элемент с искомым значением}</div><div class="code_line">&nbsp;&nbsp;{Заметьте, что если значение не найдено в списке, то в Temp окажется NIL, что вполне нам подходит}</div></ol></div></div></div></div><br>
Эти же действия удобно оформить в виде функции:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">function FindElement(FirstNode:PNode,Value:Integer):PNode;</div><div class="code_line">var Temp:PNode;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;Temp:=FirstNode;</div><div class="code_line">&nbsp;&nbsp;while Temp&#60;&#62;NIL do {Пока элемент существует}</div><div class="code_line">&nbsp;&nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp;if Temp^.Value=Value then break; {Если нашелся элемент с нужным нам значением, то прервем цикл}</div><div class="code_line">&nbsp;&nbsp; &nbsp;Temp:=Temp^.Next; {Переходим к следующему элементу}</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">&nbsp;&nbsp;FindElement:=Temp;</div><div class="code_line">end;</div></ol></div></div></div></div><br>
Должен отметить, что результатом поиска будет не значение, а указатель на элемент с искомым значением.<br>
<br>
<strong class='tag-b'><span class='tag-size' data-value='11' style='font-size:11pt;'>Вставка нового элемента в список</span></strong><br>
По уже отработанному принципу переносим воображение на толпу людей. Как мы добавим нового человека, который бы знал новую строку стиха?<br>
Для начала мы должны определиться, после какой строки будем вставлять новую строку. Логично? Потом мы по принципу поиска найдем человека, который знает ту строку, после которой мы будем вставлять нового человека. Потом мы возьмем нового человека, скажем ему строку. Затем мы узнаем, на какого человека указывает найденный нами. И скажем новому человеку, чтобы он тоже на него указывал. И в конце концов мы скажем найденному нами человеку, чтобы он указывал на нового человека.<br>
Я понимаю что это запутано, но возможно в реализации будет проще понять. Обдумайте сами представив алгоритм в голове, по ходу дела сравнивая с вот таким кодом:<br>
...Задали связаный список, хотим вставить строку NewStr после строки PrevStr. Тип данных в списке - String...<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp;{Cначала найдем элемент, после которого будем вставлять}</div><div class="code_line">&nbsp;&nbsp;Temp:=FindElement(First,PrevStr);</div><div class="code_line">&nbsp;&nbsp;{Cоздадим новый элемент}</div><div class="code_line">&nbsp;&nbsp;New(Temp2);</div><div class="code_line">&nbsp;&nbsp;Temp2^.Value:=NewStr; {Зададим значение для него}</div><div class="code_line">&nbsp;&nbsp;Temp2^.Next:=Temp^.Next; {Сделаем так, чтобы он указывал на ту же строку,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;на которую указывал элемент с PrevStr}</div><div class="code_line">&nbsp;&nbsp;Temp^.Next:=Temp2; {И наконец укажем элементом с PrevStr на наш новый элемент}</div></ol></div></div></div></div><br>
Таким образом мы ИМЕННО ВСТАВЛЯЕМ между двумя элементами <strong class='tag-b'>Temp</strong> и <strong class='tag-b'>Temp^.Next</strong> новый элемент <strong class='tag-b'>Temp2</strong>, и подправляем указатели, чтобы они составляли правильную последовательность.<br>
Тут нужно отметить то, что если строка PrevStr была в самом последнем элементе, то в списке появится новый элемент, который будет корректно последним. То есть предпоследний будет указывать на него, а новый последний элемент будет будет указывать на &quot;ничто&quot; (Next=NIL).<br>
Естественно и эти действия удобно организовать в отдельную процедуру:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Procedure InsertElement(First:PNode;PrevStr,NewStr:string);</div><div class="code_line">var</div><div class="code_line">&nbsp;&nbsp;Temp,Temp2:PNode;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;Temp:=FindElement(First, PrevStr);</div><div class="code_line">&nbsp;&nbsp;New(Temp2); { Cоздаем новый элемент}</div><div class="code_line">&nbsp;&nbsp;Temp2^.Value:=NewStr; {Зададим значение для него}</div><div class="code_line">&nbsp;&nbsp;Temp2^.Next:=Temp^.Next; {Сделаем так, чтобы он указывал на ту же строку,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;на которую указывал элемент с PrevStr}</div><div class="code_line">&nbsp;&nbsp;Temp^.Next:=Temp2; {И наконец укажем элементом с PrevStr на наш новый элемент}</div><div class="code_line">end;</div></ol></div></div></div></div><br>
При вставке нового элемента часто бывает удобно вставлять не после определенного значения элемента, а явно указывать, после какого элемента вставлять:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Procedure InsertElement2(PrevElement:PNode;NewStr:string);</div><div class="code_line">var Temp:PNode;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;New(Temp); {Cоздадим новый элемент}</div><div class="code_line">&nbsp;&nbsp;Temp^.Value:=NewStr; {Зададим значение для него}</div><div class="code_line">&nbsp;&nbsp;Temp^.Next:=PrevElement^.Next; {Сделаем так, чтобы он указывал на тот же элемент,</div><div class="code_line">&nbsp;на какой указывал PrevElement}</div><div class="code_line">&nbsp;&nbsp;PrevElement^.Next:=Temp; {И наконец укажем элементом PrevElement на наш новый элемент}</div><div class="code_line">end;</div></ol></div></div></div></div><br>
<br>
<strong class='tag-b'><span class='tag-size' data-value='11' style='font-size:11pt;'>Удаление существующего элемента из списка</span></strong><br>
Принцип: Ищем в списке элемент с заданным значением. После чего удаляем его, корректируя ссылку предыдущего элемента, чтобы он ссылался не на удаляемый элемент, а на следующий после удаляемого.<br>
Вот реализация:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Procedure DeleteElement(var First:PNode; ValueToDelete:/Тип данных/); </div><div class="code_line">{First должна быть именно var на случай, если удаляемый элемент - самый первый}</div><div class="code_line">var Temp,Temp2:PNode;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;If First^.Value=ValueToDelete then {Если удаляемый элемент - первый, то это частный случай.</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Обработаем отдельно}</div><div class="code_line">&nbsp;&nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp;Temp:=First; {Сохраним указатель на него}</div><div class="code_line">&nbsp;&nbsp; &nbsp;First:=First^.Next; {Сделаем так, чтобы первым элементом теперь стал следующий}</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dispose(Temp); {Удалим из памяти теперь уже бывший первый элемент}</div><div class="code_line">&nbsp;&nbsp; &nbsp;Break; {Окончим выполнение процедуры}</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">&nbsp;&nbsp;{Иначе мы будем искать элемент с значением ValueToDelete, но будем запоминать указатель на</div><div class="code_line">&nbsp;предыдущий элемент}</div><div class="code_line">&nbsp;&nbsp;{Это нужно для того, чтобы исправить потом указатель, чтобы он не указывал на удаленный элемент}</div><div class="code_line">&nbsp;&nbsp;Temp:=First;</div><div class="code_line">&nbsp;&nbsp;while Temp^.Next&#60;&#62;NIL do {Пока у элемента есть следующий, продолжаем}</div><div class="code_line">&nbsp;&nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp;if Temp^.Next^.Value=ValueToDelete then {Если значение следующего элемента - искомое то}</div><div class="code_line">&nbsp;&nbsp; &nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;Temp2:=temp^.Next; {Поместим в Temp2 указатель на удаляемый элемент}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;Temp^.Next:=Temp2^.Next; {Сделаем так, чтобы элемент перед удаляемым указывал на элемент</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;после удаляемого}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;Dispose(Temp2); {И наконец удалим из памяти удаляемый элемент}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;{Получится что предыдущий элемент указывает на следующий, а сам удаляемый элемент уже не существует}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;Break; {Прервём цикл, так как мы уже нашли удаляемый элемент}</div><div class="code_line">&nbsp;&nbsp; &nbsp;end;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Temp:=Temp^.Next; {Перейдем к следующему элементу}</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">end;</div></ol></div></div></div></div><br>
Так же приведу текст функции, которая удаляет элемент из списка не по значению, а по указателю на него:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Procedure DeleteElement2(var First:PNode; ElementToDelete:PNode);</div><div class="code_line">var Temp,Temp2:PNode;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;If First=ElementToDelete then {Если удаляемый элемент - первый, то это частный случай.</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Обработаем отдельно}</div><div class="code_line">&nbsp;&nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp;Temp:=First; {Сохраним указатель на него}</div><div class="code_line">&nbsp;&nbsp; &nbsp;First:=First^.Next; {Сделаем так, чтобы первым элементом теперь стал следующий}</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dispose(Temp); {Удалим из памяти теперь уже бывший первый элемент}</div><div class="code_line">&nbsp;&nbsp; &nbsp;Break; {Окончим выполнение процедуры}</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">&nbsp;&nbsp;{Иначе мы будем искать элемент ElementToDelete, но будем запоминать указатель на предыдущий</div><div class="code_line">&nbsp;&nbsp; элемент. Это нужно для того, чтобы исправить потом указатель, чтобы он не указывал на удаленный &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; элемент}</div><div class="code_line">&nbsp;&nbsp;Temp:=First;</div><div class="code_line">&nbsp;&nbsp;while Temp^.Next&#60;&#62;NIL do {Пока у элемента есть следующий продолжаем}</div><div class="code_line">&nbsp;&nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp;if Temp^.Next=ElementToDelete then {Если следующий элемент - искомый}</div><div class="code_line">&nbsp;&nbsp; &nbsp;begin</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;Temp2:=temp^.Next; {Поместим в Temp2 указатель на удаляемый элемент}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;Temp^.Next:=Temp2^.Next; {Сделаем так, чтобы элемент перед удаляемым указывал на элемент</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;после удаляемого}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;Dispose(Temp2); {И наконец удалим из памяти удаляемый элемент}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;{Получится что предыдущий элемент указывает на следующий, а сам удаляемый элемент уже не существует}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;Break; {Прервём цикл, так как мы уже нашли удаляемый элемент}</div><div class="code_line">&nbsp;&nbsp; &nbsp;end;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Temp:=Temp^.Next; {Перейдём к следующему элементу}</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">end;</div></ol></div></div></div></div><br>
<br>
<hr><br>
Итак я рассмотрел простые связанные списки, и три основных операции с ними. Остальные операции могут быть сформированы на основе этих трех.<br>
Теперь я не могу не сказать об теории списков более подробно, и не описать их классификации:<br>
Рассмотренные мной списки называются односвязными. Название такое они получили, потому что связь между элементами таких списков является односторонней - один элемент указывает на следующей, тот в свою очередь на еще один и так далее. То есть каждый элемент указывает только в одном направлении (я принял за норму - указывать на следующий элемент).<br>
Представьте себе список, в котором каждый элемент указывает не только на следующий за ним идущий, а еще и на тот, который был перед ним - на предыдущий. Если сравнивать с толпой людей, то каждый человеку указывает не на одного, а на двух сразу. Тогда одно направление указывания (последовательность людей, которые указывают друг на друга правой рукой) можно условно назвать &quot;направление вперед&quot;. А другое направление (указываемое левой рукой) - &quot;направление назад. Таким образом я смог бы перемещаться в последовательности людей не только вперед (как во всех вышеописанных примерах), а и назад. Поскольку каждый человек знает не только своего &quot;потомка&quot; но и &quot;предка&quot;.<br>
<br>
На самом деле эти направления (вперед/назад) - лишь названия, и ничего больше. Поскольку на самом деле все эти люди всего лишь куча людей. И то, в какой последовательности они друг на друга указывают руками просто определят, какого человека следует брать за каким.<br>
Вот представьте себе, что у вас есть куча переменных, организованных как ячейка связанного списка в памяти. Они все находятся в ней хаотично и не связаны друг с другом. И допустим эти переменные числа. Тогда чисто теоретически их можно взять в такой последовательности, что каждое следующее значение будет больше предыдущего. И тогда такая последовательность будет представлять собой отсортированный по возрастанию массив. И в то же время это будут оставаться хаотичные данные в памяти.<br>
А представьте себе, что у каждой из этих переменных не один параметр Next, а два. И допустим выстроены две цепочки (для одного Next и для другого) так, чтобы по одной цепочки брались элементы по возрастанию, а для другой - по убыванию. Тогда получится что у нас одни и те же данные отсортированы и по возрастанию и по убыванию. В зависимости от того, какое направление взять (Next1, или Next2). А ведь может быть и направление Next3, в котором они отсортированы в порядке их создания, и тогда для одних и тех же данных будет три направления последовательностей.<br>
Поэтому можно утверждать, что списки могут быть не только однонаправленными, а и двунаправленными, трехнаправленными, словом N-направленными. Причем сколько бы не было направлений, все они будут сделаны для одних и тех же данных. Представьте себе, если бы вам нужно было отсортировать массив по возрастанию, и по убыванию, вам бы пришлось создать два массива - один с данными по возрастанию, а другой с данными по убыванию. А тут у вас получатся ЕДИНЫЕ данные, но с двумя направлениями сортировки. Это имеет большую перспективу в том случае, к примеру, если объем данных для каждого элемента последовательности - значительный, поскольку даст существенную экономию памяти.<br>
<br>
Так-же списки бывают цикличными (замкнутыми). Это когда последний элемент списка указывает на первый элемент списка (а если список двунаправленный, то и первый может указывать на последний). У такого списка нет начала и конца, он замкнут как бы по кольцу. И по нему можно перемещаться в том или ином направлении до бесконечности, по кругу.<br>
<br>
УУФФФФ.. ну вроде-бы все на данный момент.]]></description>
        <author>Some1</author>
        <category>Pascal: Структуры данных</category>
      </item>
	
      </channel>
      </rss>
	