Lecture

Created: 25.09.2006 | Level: specialist | Access: free
Lecture 2:

Списки

< Lecture 1 || Lecture 2: 123456 || Lecture 3 >

Некоторые дополнительные операции со связными списками

Конкатенация. Эта операция предназначена для соединения двух списков в один результирующий. Она эффективна в тех случаях, когда обеспечен доступ к последнему элементу списка с трудоемкостью \[ O(1) \] . При соединении двух списков \[ S1 \] и \[ S2 \] первый элемент списка \[ S2 \] становится преемником последнего элемента списка \[ S1 \] . При этом возникают вопросы — должен ли получившийся список иметь какое-то новое имя и должны ли сохраниться как таковые исходные списки \[ S1 \] и \[ S2 \] ?

В рассмотренной ниже процедуре Concat, реализующей операцию "Соединить два списка", принято следующее решение. К списку \[ S1 \] присоединяется список \[ S2 \] , список \[ S2 \] сохраняется, а результирующим является список \[ S1 \] . Следует, однако, понимать, что если в список \[ S2 \] будут внесены изменения, они автоматически произойдут в новом списке. Трудоемкость этой операции — \[ O(1) \] .

\[ \formula{ \t{begin} \t{S1}.{\rm last}\t{\^{}}.{\rm next} := \t{S2}.{\rm first}\ \t{end}; } \]

Из списка \[ S \] удалить элементы, удовлетворяющие некоторому условию. Предположим, что требуемое условие на элемент \[ e \] проверяется предикатом condition( \[ e \] ).

\[ \formula{ \t{begin t} := \t{S}.{\rm first};\\ \mbox{}\q \t{while t} \ne {\rm nil}\ \t{do}\{\t{if condition} (\t{t\^{}}.{\rm info})\ \t{then DelPosition}(\t{S},{\rm pos});\ \t{t} := \\ \mbox{}\q \t{t\^{}}.{\rm next}\}\\ \t end; } \]

Построить список \[ S1 \] , состоящий из элементов данного списка \[ S \] , удовлетворяющих некоторому условию. Предположим, что требуемое условие на элемент \[ e \] проверяется предикатом condition ( \[ e \] ).

\[ \formula{ \t{begin} \t{t} := \t{S}.{\rm first};\ \t{SetEmpty}(\t{S1});\\ \mbox{}\q \t{while} \t{t} \ne {\rm nil} \t{do} \{\t{if} \t{condition}(\t{t\^{}}.{\rm info})\ \t{then}\ {\rm AddToEnd}(\t{e}, \t{S1});\ \t{t} := \t{t\^{}}.\t{next}\}\\ \t end; } \]

Получить список \[ S1 \] реверсированием списка \[ S \]

\[ \formula{ \t begin\\ \mbox{}\q {\rm SetEmpty}(\t{S1});\, \t{t} := \t{S}.{\rm first};\\ \mbox{}\q \t{while}\ \t{t} \ne {\rm nil}\ \t{do} \{{\rm AddToBegin}(\t{t\^{}}.{\rm inf}, \t{S1});\ \t{t} := \t{t\^{}}.{\rm next}\}\\ \t end; } \]

Моделирование списков с последовательным доступом при помощи массивов

Если использование динамических ссылок невозможно или нежелательно (тому могут быть свои причины), список со связями можно смоделировать при помощи массивов. В массиве \[ {\rm Inf} \] хранятся элементы списка, то есть значения соответствующих полей узлов списка со связями. Позицией элемента является значение целочисленного индекса массива. Кроме того, вводится целочисленный массив \[ \Next \] , в котором для каждого узла списка указана позиция, где расположен его преемник. В качестве индексного пространства используем отрезок \[ {[1\ldots n]} \] целочисленного типа.

В одних и тех же массивах \[ {\rm Inf} \] и \[ \Next \] могут размещаться сразу несколько списков, состоящих из узлов одного типа. С учетом такого возможного сосуществования различных списков их элементы могут размещаться в этих массивах хаотично, подобно тому, как узлы списков, представленных с помощью ссылок, могут произвольно располагаться в памяти компьютера.

На табл. 2.1 показано возможное заполнение массивов \[ {\rm Inf} \] и \[ {\rm Next} \] для одностороннего списка, представляющего кортеж \[ (a, b, c, d, e) \] (пустые клетки не имеют отношения к этому списку).

Таблица 2.1. Моделирование одностороннего списка при помощи массива
Адрес 1 2 3 4 5 6 7 8 9 10 11 12
Inf e b c d a
Next 0 6 9 1 3

Доступ к списку можно осуществить через его первый элемент, позиция которого в массиве задается значением переменной \[ {\rm first} = 11 \] . Значение \[ \Next[1] = 0 \] говорит о том, что в позиции \[ 1 \] расположен элемент, у которого нет преемника, то есть последний элемент кортежа.

На табл. 2.2 показано возможное заполнение массивов \[ {\rm Inf} \] , \[ \rm Next \] и \[ \rm Precede \] для представления кортежа ( \[ a, b, c, d, e \] ) двусторонним списком.

Таблица 2.2. Моделирование двустороннего списка при помощи массивов
Адрес 1 2 3 4 5 6 7 8 9 10 11 12
Inf e b c d a
Next 0 6 9 1 3
Precede 9 11 3 6 0

Основные отображения \[ {\rm Info}({\rm pos}) \] , \[ {\rm Next}({\rm pos}) \] , \[ {\rm Precede}({\rm pos}) \] , \[ {\rm First} \] , \[ {\rm Last} \] , \[ {\rm Length} \] задаются очевидным образом. Если какие-либо из них не заданы явно, то их можно вычислять через другие сканированием списка.

Чтобы одни и те же массивы \[ {\rm Info} \] , \[ {\rm Next} \] , \[ {\rm Precede} \] использовать для одновременного хранения нескольких однотипных списков, позиции этих массивов объединяют в один так называемый свободный список \[ {\rm Avail} \] . Это можно сделать, например, с помощью операторов

\[ \formula{ \t begin\\ \mbox{} \q {\rm Avail}.{\rm first} :=1;\ {\rm Next}[\t{n}] := 0;\ \t{for}\ i:= 1\ \t{to}\ \t{n} - 1\ \t{do}\ {\rm Next}[\t{i}]:= \t{i} + 1;\\ \mbox{} \q {\rm Preced}[1]:= 0;\ \t{for}\ \t{i}:= 2\ \t{to}\ \t{n}\ \t{do}\ {\rm Preced}[i]:= \t{i} - 1;\\ \t{end}; } \]

Массив \[ {\rm Info} \] при этом не заполняется. При создании новых списков используются элементы массивов \[ {\rm Info} \] , \[ {\rm Next} \] , \[ {\rm Precede} \] , предварительно удаляемые из списка \[ {\rm Avail} \] . В момент создания нового узла из списка \[ {\rm Avail} \] удаляется головной элемент, который и используется для добавления в новый список. С другой стороны, при удалении элемента из какого-либо списка освобождаемая позиция добавляется к свободному списку для последующего использования. Такая техника применялась, когда системы программирования не имели стандартных средств динамического выделения памяти. Однако в условиях ограниченной памяти этот прием можно использовать и сейчас. Дело в том, что при достаточно большом объеме оперативной памяти стандартные системы вынуждены использовать многоразрядную адресацию, в то время как для позиционирования в массивах \[ {\rm Info} \] , \[ {\rm Next} \] , \[ {\rm Precede} \] можно задействовать малоразрядные представления чисел.

< Lecture 1 || Lecture 2: 123456 || Lecture 3 >