Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
адреси та вказівники.doc
Скачиваний:
2
Добавлен:
27.08.2019
Размер:
1.15 Mб
Скачать

Поняття динамічного лінійного списку

Лінійні списки у вільній пам'яті та найпростіші операції з ними (додавання й вилучення елементів) розглянемо за допомогою за­дачі.

Задача.

Кожен рядок текстового файлу є прізвищем; прізвища можуть повторюватися. Треба прочитати текст і надрукувати кожне прізвище по одному разу. Порядок прізвищ не має значення.

Пояснення до розв'язання

Позначимо текстовий файл ім'ям f, черговий рядок — s, а по­слідовність прочитаних рядків — sqs. Спочатку sqs порожня — позначимо це символами < >. Алгоритм розв'язання очевидний:

підготувати f до обробки

sqs : = < >;

while not eof(f) do begin

readln(f,s)

If not (s належить sqs) then

додати s до sqs;

end;

надрукувати елементи sqs.

Умова задачі не обмежує кількості елементів у послідовності sqs, тому для її збереження масив непридатний. Використаємо лінійний зв'язаний список рядків у вільній пам'яті. Елемента­ми списку є структури (записи) такого типу.

Рядок

Вказівник на наступний елемент

Ці структури утворюють послідовність, подану на рис. 3. Пер­ший елемент називається головним елементом, або головою. Поле-вказівник кожного елемента списку (крім останнього) виз­начає наступний елемент, «прив'язуючи» його до попереднього. За останнім елементом списку наступного немає, тому його вка­зівник має значення nil.

Рис. 3. Зв'язаний список рядків

• Якщо розірвати зв'язок із попереднім елементом, змінив­ши значення вказівника в ньому, втрачається посилання на наступний елемент списку. Цей елемент і всі після нього ста­ють недоступними у програмі, тобто «сміттям» у вільній па­м'яті.

• Для доступу до першого елемента й усього списку потрібен вказівник на голову списку, оголошений у програмі й розташова­ний у її статичній або автоматичній пам'яті.

Розглянемо оголошення й операції, потрібні для обробки списку.

Елементи списку є структурами, в яких одне поле є вказівни­ком на структури цього ж типу. Що оголосити спочатку — тип структур чи тип вказівників на них? Вказівники будь-якого типу мають розмір 4 байти, тому спочатку оголошується тип вказів­ників на структури, а потім — тип структур.

type Pstr=^Lstr; (тип вказівників}

Lstr=record {тип елементів списку рядків}

V : string;

next : Pstr;

end;

Елемент списку, на який встановлено вказівник р типу Pstr, позначається виразом р^. Вирази р^. vi р^. next позначають поля елемента — рядок типу string і адресу наступного елемента типу Pstr.

Проте список рядків або інших даних, особливо великого роз­міру, краще організувати інакше. Замість даних, наприклад рядків, елемент списку містить вказівник на них, а самі вони збе­рігаються в купі окремо (рис. 4).

Рис. 4. Список вказівників на рядки

Така організація особливо зручна, якщо дані в списку треба обмінювати місцями.

Наприклад, нехай список має елементи типу Lstr, оголоше­ного вище. На два елементи списку встановлено вказівники р1 і р2 типу Pstr, і ці елементи треба поміняти місцями. Для цього можна поміняти місцями рядки, як у таких операторах (s — до­поміжна змінна типу string).

s:=pl^.v; pl^.v:=p2^.v; p2^.v:=s

Проте тут тричі переміщуються рядки розміром по 256 байт, а таких переміщень краще уникати.

Оголосимо типи по-іншому.

type Pstring=^string; {тип вказівників на рядки} PElem=^Elem; {та на елементи списку}

Elem=record {тип елементів списку)

pval: Pstring;

next: Pelem;

end;

За цих оголошень, якщо вказівник р типу PElem установлено на елемент списку, то вирази р^ .pval і р^.next позначають поля елемента — вказівники на рядок і на наступний елемент типу PElem, а р^. pval^ — сам рядок.

Якщо вказівники рі і р2 типу PElem встановлено на два еле­менти списку, то для обміну рядків досить обміняти 4-байтові вказівники на рядки (р — допоміжний вказівник типу Pstring).

p:=pl^.pval;

pl^.pval:=р2^.pval;

p2^.pval := р;

Оголошення типів Pstring, PEelem і Elem використовуються нижче.