Дмитриева Марина Валерьевна
ОСНОВНЫЕ АЛГОРИТМЫ РАБОТЫ С ЛИНЕЙНЫМИ ЦЕПНЫМИ СПИСКАМИ
При создании любой сложной структуры данных надо уметь решать задачи поиска, то есть определять, принадлежит ли некоторый элемент построенному множеству элементов. Применительно к списку задача поиска конкретизируется следующим образом: требуется определить, имеется ли в списке элемент, информационное поле которого совпадает с заданным значением (образцом).
Возможны два варианта ответа на вопрос, найден ли элемент в списке. В первом случае можно выдавать логическое значение true, если элемент найден, и false в противном случае. Во втором варианте в качестве ответа может быть ссылка на найден-
|| ¡<
срме&ь ремлЛл j&pazu плиосл,,,
ный элемент или значение Nil, если элемента в списке не обнаружено.
При описании процедур работы со списками будем считать, что определены структуры данных, представленные в листинге 1.
ПОИСК ЭЛЕМЕНТА В СПИСКЕ.
ВАРИАНТ 1
Пусть задан линейный список с указателем t на первый элемент. Требуется определить, есть ли в списке элемент с заданным значением r информационного поля.
Указатель cur устанавливается на текущий элемент, в начальный элемент он совпадает с t. Для поиска элемента в линейном списке поступаем следующим образом. Сравниваем значение информационного поля текущего элемента со значением r. Если значения совпадают, то задача решена, в противном случае требуется перейти к следующему элементу списка.
Процесс просмотра элементов списка продолжается до тех пор, пока не будет найден соответствующий элемент, либо пока не исчерпается весь список. В последнем случае нужного элемента в списке нет.
Листинг 1. Описание структур данных для работы с линейными списками
type
elem_list = integer; {тип информационного поля элемента списка} list = Aelem; (указатель на элемент списка)
elem= record info: elem_list; (информационное поле элемента списка) next: list {указатель на следующий элемент}
end;
Дмитриева M.B.
Рис. 1. Поиск элемента в списке
Функция, осуществляющая поиск элемента в линейном списке, приведена в листинге 2. Функция выдает значение true, если элемент найден, и false в противном случае.
На рис. 1 изображена ситуация в точке {1}, которую можно описать так: просмотрен линейный список до элемента, предшествующего элементу, на который установлен указатель cur. Среди просмотренных элементов нет элемента с заданным информационным полем (равного образцу).
Указатель cur установлен на первый элемент непросмотренной части списка. В точке {1} верно и следующее утверждение: не про-
'Ироцесс afeocMO&fia с*иижа...
смотренная часть списка не пуста. Точка {2} соответствует тому, что цикл завершил свою работу, значение переменной cur равно nil, список просмотрен полностью, элемент не найден.
ПОИСК ЭЛЕМЕНТА В СПИСКЕ.
ВАРИАНТ 2
Приведем еще один вариант описания функции поиска элемента в линейном списке, использующий особенности структур данных языка Паскаль. Описание функции приведено в листинге 3.
Листинг 2. Поиск элемента в списке. Вариант 1
function searchl (var t: list; r: elem list): boolean;
var cur: list;
begin searchl := false;
cur := t;
while cur <> nil do {1}
if curA.info = r
then
begin searchl := true; exit end
else cur := curA.next {2}
end
Листинг 3. Поиск элемента в списке. Вариант 2
Function search2 (var t: list; r: elem_list): boolean;
var cur: list; sel: Boolean; begin sel := false; cur := t;
while sel < (cur <> nil) do begin sel := curA.info = r; cur := curA.next
end; search2 := sel
end
sel < (cur <> nil) также станет равным false, и цикл завершит свою работу.
Если же просмотрен весь список и в нем нет элемента с информационным полем r, то значение переменной sel равно false, значение выражения cur<>nil после просмотра всего списка равно false. Формула false < false имеет значение false, поэтому работа цикла будет завершена. Результат поиска совпадает со значением переменной sel.
СОРТИРОВКА СПИСКА
...алгари&м сор&ироёки миЛейЛага списка á oopfrfKe áofjíac&aftu#....
Напомним, что стандартный тип Boolean считается перечислимым типом, определенным следующим образом: type Boolean = (false, true). Так как
элементы в перечислимом типе считаются упорядоченными, то верно соотношение false < true. Тело цикла выполняется, если истинно выражение sel < (cur <> nil).
Если в списке найден элемент с информационным полем r, то значение логической переменной sel станет равным true в результате выполнения оператора присваивания sel: =curA. info=r. Так как значение выражения true < L ложно при любом значении логической переменной L, то выражение, управляющее работой цикла
Предположим, что на элементах, из которых строится список, задано отношение порядка. Рассмотрим алгоритм сортировки линейного списка в порядке возрастания значений информационных полей его элементов.
Пусть список задан указателем на первый элемент ^ Будем использовать два указателя р и д, указатель р устанавливается на очередной элемент списка, указатель д пробегает значения от элемента, непосредственно следующего за тем, на который установлен указатель р, до конца списка.
Сравниваются информационные поля элементов и s2), на которые установлены указатели р и д. Если верно, что s1 > s2, то информационные поля меня-
Листинг 4. Сортировка списка в порядке возрастания информационных полей
procedure sort_list (var t: list);
var p,q: list; r: elem list;
begin p:=t;
while p <> nil do
begin
q:= pA- next;
while q <> nil do
begin if pA.info > qA.info
then
begin
r := pA.info;
pA.info := qA.info;
qA.info :=r
end;
q := qA.next
end;
p := pA .next {1}
end
end
Дмитриева М.В.
Рис. 2. Сортировка элементов списка в порядке возрастания
ются местами. После того, как для фиксированного р переменная д пробежит значения до конца списка, элемент, на который указывает р, имеет информационное поле, наименьшее из всех информационных полей следующих за ним элементов.
Дальнейшие действия состоят в том, чтобы перейти к следующему за р (если он есть) элементу списка и для него повторить: установить указатель д на следующий за р элемент и сравнить информационные поля элемента, на который установлен указатель р, и всех следующих за ним элементов.
Если просмотрен весь список, то анализ списка завершен и элементы списка упорядочены. До начала просмотра списка значение р совпадает с Ъ, указатель д установлен на второй элемент списка, если список содержит более одного элемента. Процедура, осуществляющая сортировку элементов списка в порядке возрастания информационных полей, приведена в листинге 4.
На рис. 2 представлена ситуация, когда список, предшествующий элементу, на который установлен указатель р, уже отсортирован, указатель д установлен на эле-
мент, непосредственно следующий за p. После того как указатель q «пробежит» по всем элементам «хвоста» списка, элемент, на который установлен указатель p, будет иметь наименьшее значение информационного поля из всех элементов «хвоста» списка.
После перехода к следующему элементу списка в точке {1} просмотренная часть списка (начало списка) отсортирована. Значение p, равное nil, будет означать, что просмотрен весь список и его элементы расположены в порядке возрастания.
СЛИЯНИЕ ДВУХ УПОРЯДОЧЕННЫХ СПИСКОВ
Рассмотрим два упорядоченных списка. Задача слияния двух упорядоченных списков состоит в формировании упорядоченного списка, состоящего из тех же элементов, что и исходные. Результирующий список должен быть упорядоченным.
Для решения задачи будем параллельно просматривать два списка с указателями t и p. Пусть t1 - указатель на первый элемент непросмотренной части первого списка, указатель pi устанавливается на текущий элемент второго списка. В начальный момент времени оба указателя установлены на первые элементы списков (если списки не пусты).
Все просмотренные элементы хранятся в списке с указателем на первый элемент s, указатель si установлен на последний элемент построенного (уже слитого) списка. Естественно, сначала формируемый список пуст. Сравниваем информационные поля
Рис. 3. Слияние двух упорядоченных списков
SafAM
ух ymftflfmefrfrux
Листинг 5. Процедура слияния двух упорядоченных списков
procedure sl_list (var t, p, s: list);
var tl, pi, s1: list;
begin if t = nil then s := p else if p= nil then s := t
else {оба списка не пусты}
begin
tl := t; pi := p;
if tiA.info < piA.info
then begin s := tl; tl := tiA.next end
else begin s := pi; pi := piA.next end;
si:=s;
while (ti <> nil) and (pi <> nil) do
begin if tiA.info < piA.info
then begin siA.next :=ti; ti := tiA.next end
else begin siA.next :=pi; pi := piA.next end;
si:=siA.next
end
end
end
элементов, на которые установлены указатели и р1.
Тот элемент, информационное поле которого меньше, добавляется в конец формируемого списка, а указатель в соответствующем списке сдвигается на следующий элемент списка.
Просмотр списков следует продолжать до тех пор, пока не исчерпается один из списков. Процедура слияния двух упорядоченных списков приведена в листинге 5.
На рис. 3 изображена ситуация, когда просмотрены элементы первого списка до элемента с указателем Ъ1, просмотрены элементы второго списка до элемента с указателем р1, просмотренные части обоих списков «слиты», указатель б установлен на первый элемент списка-результата, указатель б1 установлен на последний элемент формируемого списка.
Просмотр списков продолжается, пока не исчерпается один из них. Не просмотренная часть другого списка составляет «хвост» списка результата.
Дмитриева Марина Валерьевна, доцент кафедры информатики математико-механического факультета Санкт-Петербургского государственного университета.
ЗАДАЧИ
1. Опишите функцию, которая определяет число элементов в списке, информационные поля которых совпадают с заданным значением.
2. Опишите функцию, которая проверяет, имеются ли в списке элементы, непосредственно следующие друг за другом, информационные поля которых одинаковы.
3. Опишите функцию, которая определяет, образуют ли элементы списка возрастающую последовательность.
4. Опишите следующую модификацию рассмотренной процедуры сортировки линейного списка. При каждом фиксированном значении р определите указатель на элемент с минимальным значением информационного поля для элементов, следующих за Р, и лишь затем в случае необходимости меняйте значения информационных полей.
5. Опишите процедуру слияния двух упорядоченных списков, исходные списки должны остаться без изменения.
Наши авторы. 2007 Our authors, 2007