Опубликован: 03.09.2010 | Уровень: для всех | Доступ: платный
Лекция 5:

Работа с динамической памятью

< Лекция 4 || Лекция 5: 1234 || Лекция 6 >

Линейные списки

В линейном списке каждый элемент связан со следующим и, возможно, с предыдущим. В первом случае список называется односвязным, во втором — двусвязным. Также применяются термины "однонаправленный" и "двунаправленный". Если последний элемент связать указателем с первым, получится кольцевой список.

Каждый элемент списка содержит ключ, идентифицирующий этот элемент. Ключ обычно бывает либо целым числом, либо строкой и является частью поля данных. В качестве ключа в процессе работы со списком могут выступать разные части поля данных. Например, если создается линейный список из записей, содержащих фамилию, год рождения, стаж работы и пол, любая часть записи может выступать в качестве ключа. При упорядочивании списка по алфавиту ключом будет фамилия, а при поиске, например, ветеранов труда — стаж. Ключи разных элементов списка могут совпадать.

Над списками можно выполнять следующие операции:

  1. начальное формирование списка (создание первого элемента);
  2. добавление элемента в конец списка;
  3. чтение элемента с заданным ключом;
  4. вставка элемента в заданное место списка (до или после элемента с заданным ключом);
  5. удаление элемента с заданным ключом;
  6. упорядочивание списка по ключу.

Стек и очередь представляют собой частные случаи линейного списка с ограниченным набором допустимых операций.

При чтении элемент списка не удаляется, в отличие от элемента, выбираемого из стека и очереди. Для работы со списком в программе требуется определить указатель на его начало. Чтобы упростить добавление новых элементов в конец списка, можно также завести указатель на конец списка.

Рассмотрим программу ( пример 5.3), которая формирует односвязный список из пяти элементов, содержащих число и его текстовое представление, а затем выполняет вставку и удаление заданного элемента. В качестве ключа используется число.

program linked_list;
const n = 5;
type pnode = ^node;
     node = record                                             { элемент списка }
         d : word; 
         s : string;
         p : pnode;
     end;
var beg    : pnode;                                { указатель на начало списка }
    i, key : word;
    s      : string;
    option : word;
const text: array [1 .. n] of string = ('one', 'two', 'three', 'four', 'five');
{ -------------- добавление элемента в конец списка --------------------------- }
procedure add(var beg : pnode; d : word; const s : string);
var p : pnode;                               { указатель на создаваемый элемент }
    t : pnode;                                 { указатель для просмотра списка }
begin
    new(p);                                                 { создание элемента }
    p^.d := d; p^.s := s;                                 { заполнение элемента }
    p^.p := nil;
    if beg = nil then beg := p                                { список был пуст }
    else begin                                                 { список не пуст }
        t := beg;
        while t^.p <> nil do                        { проход по списку до конца }
            t := t^.p;            
        t^.p := p;                      { привязка нового элемента к последнему }
    end
end;
{ ------------------------- поиск элемента по ключу --------------------------- }
function find(beg : pnode; key : word; var p, pp : pnode) : boolean;
begin
    p := beg;
    while p <> nil do begin                                                 { 1 }
        if p^.d = key then begin                                            { 2 }
            find := true; exit end;
        pp := p;                                                            { 3 }
        p := p^.p;                                                          { 4 }
    end;
    find := false;
end;

{ -------------------------------- вставка элемента --------------------------- }
procedure insert(beg : pnode; key, d : word; const s : string);
var p    : pnode;                            { указатель на создаваемый элемент }
    pkey : pnode;                                { указатель на искомый элемент }
    pp   : pnode;                             { указатель на предыдущий элемент }
begin
    if not find(beg, key, pkey, pp) then begin
        writeln(' вставка не выполнена'); exit; end;
    new(p);                                                                 { 1 }
    p^.d := d; p^.s := s;                                                   { 2 }
    p^.p := pkey^.p;                                                        { 3 }
    pkey^.p := p;                                                           { 4 }
end;
{ ------------------------------- удаление элемента --------------------------- }
procedure del(var beg : pnode; key : word);
var p  : pnode;         { указатель на удаляемый элемент }
    pp : pnode;         { указатель на предыдущий элемент }
begin
    if not find(beg, key, p, pp) then begin 
        writeln(' удаление не выполнено'); exit; end; 
    if p = beg then beg := beg^.p                   { удаление первого элемента }
    else pp^.p := p^.p;
    dispose(p);
end;
{ ------------------------------------ вывод списка --------------------------- }
procedure print(beg : pnode);
var p : pnode;                                 { указатель для просмотра списка }
begin
    p := beg;
    while p <> nil do begin                                    { цикл по списку }
        writeln(p^.d:3, p^.s);                                 { вывод элемента }
        p := p^.p                        { переход к следующему элементу списка }
    end;
end;
{ ------------------------------- главная программа --------------------------- }
begin
    for i := 1 to 5 do add(beg, i, text[i]);
    while true do begin 
        writeln('1 - вставка, 2 - удаление, 3 - вывод, 4 - выход');
        readln(option);
        case option of
            1: begin                                                  { вставка }
                writeln('Ключ для вставки?');
                readln(key);
                writeln('Вставляемый элемент?');
                readln(i); readln(s);
                insert(beg, key, i, s);
            end;
            2: begin                                                 { удаление }
                writeln('Ключ для удаления?');   
                readln(key);
                del(beg, key);
            end;
            3: begin                                                    { вывод }
                writeln('Вывод списка:');
                print(beg);
            end;
            4: exit;                                                    { выход }
        end
        writeln;
    end
end.
Листинг 5.3. Использование списка

Функция поиска элемента find возвращает true, если искомый элемент найден, и false в противном случае. Поскольку одного факта отыскания элемента недостаточно, функция также возвращает через список параметров два указателя: на найденный элемент p и на предшествующий ему pp. Последний требуется при удалении элемента из списка, поскольку при этом необходимо связывать предыдущий и последующий по отношению к удаляемому элементы.

Сначала указатель p устанавливается на начало списка, и организуется цикл просмотра списка (оператор 1). Если поле данных очередного элемента совпало с заданным ключом (оператор 2), формируется признак успешного поиска и функция завершается. В противном случае перед переносом указателя на следующий элемент списка (он хранится в поле p текущего элемента, оператор 4) его значение запоминается в переменной pp (оператор 3) для того, чтобы при следующем проходе цикла в ней находился указатель на предыдущий элемент.

Если элемента с заданным ключом в списке нет, цикл завершится естественным образом, поскольку последний элемент списка содержит nil в поле p указателя на следующий элемент.

Вставка элемента выполняется после элемента с заданным ключом (процедура insert ). Если с помощью функции find место вставки определить не удалось, выводится сообщение и процедура завершается (в этом случае можно было использовать и другой алгоритм — добавлять элемент к концу списка, это определяется конкретным предназначением программы). Если элемент найден, указатель на него заносится в переменную pkey.

Под новый элемент выделяется место в динамической памяти (оператор 1), и информационные поля элемента заполняются переданными в процедуру значениями (оператор 2). Новый элемент p вставляется между элементами pkey и следующим за ним (его адрес хранится в pkey^.p ). Для этого в операторах 3 и 4 устанавливаются две связи ( рис. 5.4).

 Вставка элемента в список

Рис. 5.4. Вставка элемента в список

Удаление элемента выполняет процедура del. В ней две ветви, поскольку при удалении элемента из начала списка изменяется указатель на начало, а при удалении второго и последующих элементов требуется связывать предыдущий и последующий по отношению к удаляемому элементы.

< Лекция 4 || Лекция 5: 1234 || Лекция 6 >
София Шишова
София Шишова

Я завершила экзамен 90 баллов на 5. Сертификат не заказала. Сейчас пытаюсь найти как его заказать. у меня указано экзамен пройден баллы оценка видно, а чтоб заказать сертификат нигде не видно.

Игорь Тарасов
Игорь Тарасов
Россия, г. Астрахань
Венера Имамова
Венера Имамова
Россия