Опубликован: 26.09.2006 | Доступ: свободный | Студентов: 1800 / 485 | Оценка: 4.25 / 4.12 | Длительность: 17:09:00
ISBN: 978-5-9556-0066-6
Специальности: Программист, Математик
Лекция 2:

Списки

< Лекция 1 || Лекция 2: 123456 || Лекция 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} можно задействовать малоразрядные представления чисел.

< Лекция 1 || Лекция 2: 123456 || Лекция 3 >
Антон Сиротинкин
Антон Сиротинкин

на стр 6, лекции 3, Очевидно "Ck <= модуль(Gk(е))*b(k+1)" (1) - , подскажите что значит "модуль" и почему это очевидно...