Списки Динамические структуры данных. 2 Строение: набор узлов, объединенных с помощью ссылок. Как устроен узел: данные ссылки на другие узлы Типы структур:

Презентация:



Advertisements
Похожие презентации
1 Программирование на языке Паскаль Файлы с последовательным доступом. Кулебякин В.В.
Advertisements

Указатели Динамические структуры данных. 2 Статические данные переменная (массив) имеет имя, по которому к ней можно обращаться размер заранее известен.
Файловый тип данных Файл – это область памяти на внешнем носителе, в которой хранится некоторая информация. В языке Паскаль файл представляет собой последовательность.
Работа с файлами.. Процедура Assign(var f; name : String); Связывает внешний файл с именем name и переменную файлового типа f. Все дальнейшие операции.
Множества значений или переменных с одним общим именем называются структурированными типами. По способу организации и типу компонентов выделяют: 1. Массивы.
1 Программирование на языке Паскаль Тема: Файлы. Integer, Real, Boolean, Character, String, Text.
1 Записи 2 Запись – это тип данных, который может включать в себя несколько полей – элементов разных типов (в том числе и другие структуры). Свойства:
Списки Лекция 10. Списки Список – структура данных, представляющая собой конечную последовательность элементов. Элемент списка: Данные Связь.
Файловый тип данных Turbo Pascal Операции для работы с файлами 11 класс.
Программирование на языке Паскаль Файлы комбинированного типа (записей)
Динамічні структури даних.. 2 Динамические данные размер заранее неизвестен, определяется во время работы программы память выделяется во время работы.
Рекурсивная обработка списков1 Структуры и алгоритмы обработки данных, 1 Лекция 3 Рекурсивная обработка списков 1.Представление и реализация.
Program wr_text; var f: text; st: integer; i:integer; begin assign(f,'l1.TXT'); rewrite(f); write('вводите поочередно числа, после ввода очередного числа.
Пусть нам необходимо сформировать текстовый файл с помощью Паскаля, а затем переписать из данного файла во второй только те строки, которые начинаются.
Файловый ввод- вывод данных в Pascalе Средства обработки файлов 11 класс Дугина Ирина Радиковна, учитель информатики и ИКТ, МБОУ СОШ с.Камышки Александрово-Гайского.
ТЕКСТОВЫЕ ФАЙЛЫ Turbo Pascal 7.0. Операции с текстовыми файлами Выделение буфера обмена Установка связи Открытие файла Чтение из файла Запись в файл Закрытие.
Реализация списков:динамические структуры ListList clasclas структура одного элемента type LIST = celltype; celltype = record element: eltype; next: LIST.
САОД кафедра ОСУ 1 Основные абстрактные типы данных Схема процесса создания программ для решения прикладных задач ВУ.
1 Файловый тип данных Файл – это область памяти на внешнем носителе, в которой хранится некоторая информация. Файл – это набор данных, хранящихся во внешней.
Линейные списки – это структура данных, каждый элемент которой связывается со следующим с помощью указателя. Список.
Транксрипт:

Списки Динамические структуры данных

2 Строение: набор узлов, объединенных с помощью ссылок. Как устроен узел: данные ссылки на другие узлы Типы структур: списки деревья графы nil односвязный двунаправленный (двусвязный) циклические списки (кольца) nil

3 Когда нужны списки? Задача (алфавитно-частотный словарь). В файле записан текст. Нужно записать в другой файл в столбик все слова, встречающиеся в тексте, в алфавитном порядке, и количество повторений для каждого слова. Проблемы: 1)количество слов заранее неизвестно (статический массив); 2)количество слов определяется только в конце работы (динамический массив). Решение – список. Алгоритм: 1)создать список; 2)если слова в файле закончились, то стоп. 3)прочитать слово и искать его в списке; 4)если слово найдено – увеличить счетчик повторений, иначе добавить слово в список; 5)перейти к шагу 2.

4 Что такое список: 1)пустая структура – это список; 2)список – это начальный узел (голова) и связанный с ним список. Списки: новые типы данных type PNode = ^Node; { указатель на узел } Node = record { структура узла } word: string[40]; { слово } count: integer; { счетчик повторений } next: PNode; { ссылка на следующий } end; type PNode = ^Node; { указатель на узел } Node = record { структура узла } word: string[40]; { слово } count: integer; { счетчик повторений } next: PNode; { ссылка на следующий } end; Новые типы данных: Адрес начала списка: var Head: PNode;... Head := nil; var Head: PNode;... Head := nil; Рекурсивное определение! ! ! nil Для доступа к списку достаточно знать адрес его головы! ! !

5 Что нужно уметь делать со списком? 1. Создать новый узел. 2. Добавить узел: а) в начало списка; б) в конец списка; в) после заданного узла; г) до заданного узла. 3. Искать нужный узел в списке. 4. Удалить узел.

6 Создание узла function CreateNode(NewWord: string): PNode; var NewNode: PNode; begin New(NewNode); NewNode^.word := NewWord; NewNode^.count := 1; NewNode^.next := nil; Result := NewNode; end; function CreateNode(NewWord: string): PNode; var NewNode: PNode; begin New(NewNode); NewNode^.word := NewWord; NewNode^.count := 1; NewNode^.next := nil; Result := NewNode; end; Функция CreateNode (создать узел): вход: новое слово, прочитанное из файла; выход: адрес нового узла, созданного в памяти. возвращает адрес созданного узла новое слово Если память выделить не удалось? ? ?

7 Добавление узла в начало списка NewNode Head nil 1) Установить ссылку нового узла на голову списка: NewNode^.next := Head; NewNode Head nil 2) Установить новый узел как голову списка: Head := NewNode; procedure AddFirst ( var Head: PNode; NewNode: PNode ); begin NewNode^.next := Head; Head := NewNode; end; procedure AddFirst ( var Head: PNode; NewNode: PNode ); begin NewNode^.next := Head; Head := NewNode; end; var адрес головы меняется

8 Добавление узла после заданного 1) Установить ссылку нового узла на узел, следующий за p : NewNode^.next = p^.next; 2) Установить ссылку узла p на новый узел: p^.next = NewNode; NewNode p p nil NewNode p p nil procedure AddAfter ( p, NewNode: PNode ); begin NewNode^.next := p^.next; p^.next := NewNode; end; procedure AddAfter ( p, NewNode: PNode ); begin NewNode^.next := p^.next; p^.next := NewNode; end;

9 Задача: сделать что-нибудь хорошее с каждым элементом списка. Алгоритм: 1)установить вспомогательный указатель q на голову списка; 2)если указатель q равен nil (дошли до конца списка), то стоп; 3)выполнить действие над узлом с адресом q ; 4)перейти к следующему узлу, q^.next. Проход по списку var q: PNode;... q := Head; // начали с головы while q nil do begin // пока не дошли до конца... // делаем что-то хорошее с q q := q^.next; // переходим к следующему end; var q: PNode;... q := Head; // начали с головы while q nil do begin // пока не дошли до конца... // делаем что-то хорошее с q q := q^.next; // переходим к следующему end; Head nil q q

10 Добавление узла в конец списка Задача: добавить новый узел в конец списка. Алгоритм: 1)найти последний узел q, такой что q^.next равен nil ; 2)добавить узел после узла с адресом q (процедура AddAfter ). Особый случай: добавление в пустой список. procedure AddLast ( var Head: PNode; NewNode: PNode ); var q: PNode; begin if Head = nil then AddFirst ( Head, NewNode ) else begin q := Head; while q^.next nil do q := q^.next; AddAfter ( q, NewNode ); end; procedure AddLast ( var Head: PNode; NewNode: PNode ); var q: PNode; begin if Head = nil then AddFirst ( Head, NewNode ) else begin q := Head; while q^.next nil do q := q^.next; AddAfter ( q, NewNode ); end; особый случай – добавление в пустой список ищем последний узел добавить узел после узла q

11 Проблема: нужно знать адрес предыдущего узла, а идти назад нельзя! Решение: найти предыдущий узел q (проход с начала списка). Добавление узла перед заданным NewNode p p nil procedure AddBefore(var Head: PNode; p, NewNode: PNode); var q: PNode; begin q := Head; if p = Head then AddFirst ( Head, NewNode ) else begin while (q nil) and (q^.next p) do q := q^.next; if q nil then AddAfter ( q, NewNode ); end; procedure AddBefore(var Head: PNode; p, NewNode: PNode); var q: PNode; begin q := Head; if p = Head then AddFirst ( Head, NewNode ) else begin while (q nil) and (q^.next p) do q := q^.next; if q nil then AddAfter ( q, NewNode ); end; в начало списка ищем узел, следующий за которым – узел p добавить узел после узла q Что плохо? ? ?

12 Добавление узла перед заданным (II) Задача: вставить узел перед заданным без поиска предыдущего. Алгоритм: 1)поменять местами данные нового узла и узла p ; 2)установить ссылку узла p на NewNode. procedure AddBefore2 ( p, NewNode: PNode ); var temp: Node; begin temp := p^; p^ := NewNode^; NewNode^ := temp; p^.next := NewNode; end; procedure AddBefore2 ( p, NewNode: PNode ); var temp: Node; begin temp := p^; p^ := NewNode^; NewNode^ := temp; p^.next := NewNode; end; NewNode p p nil Так нельзя, если p = nil или адреса узлов где-то еще запоминаются! ! ! NewNode p p nil

13 Поиск слова в списке Задача: найти в списке заданное слово или определить, что его нет. Функция Find : вход: слово (символьная строка); выход: адрес узла, содержащего это слово или nil. Алгоритм: проход по списку. function Find(Head: PNode; NewWord: string): PNode; var q: PNode; begin q := Head; while (q nil) and (NewWord q^.word) do q := q^.next; Result := q; end; function Find(Head: PNode; NewWord: string): PNode; var q: PNode; begin q := Head; while (q nil) and (NewWord q^.word) do q := q^.next; Result := q; end; ищем это слово результат – адрес узла или nil (нет такого) while (q nil) and (NewWord q^.word) do q := q^.next; пока не дошли до конца списка и слово не равно заданному

14 Куда вставить новое слово? Задача: найти узел, перед которым нужно вставить, заданное слово, так чтобы в списке сохранился алфавитный порядок слов. Функция FindPlace : вход: слово (символьная строка); выход: адрес узла, перед которым нужно вставить это слово или nil, если слово нужно вставить в конец списка. function FindPlace(Head: PNode; NewWord: string): PNode; var q: PNode; begin q := Head; while (q nil) and (NewWord > q^.word) do q := q^.next; Result := q; end; function FindPlace(Head: PNode; NewWord: string): PNode; var q: PNode; begin q := Head; while (q nil) and (NewWord > q^.word) do q := q^.next; Result := q; end; > слово NewWord стоит по алфавиту перед q^.word

15 Удаление узла procedure DeleteNode ( var Head: PNode; p: PNode ); var q: PNode; begin if Head = p then Head := p^.next else begin q := Head; while (q nil) and (q^.next p) do q := q^.next; if q nil then q^.next := p^.next; end; Dispose(p); end; procedure DeleteNode ( var Head: PNode; p: PNode ); var q: PNode; begin if Head = p then Head := p^.next else begin q := Head; while (q nil) and (q^.next p) do q := q^.next; if q nil then q^.next := p^.next; end; Dispose(p); end; while (q nil) and (q^.next p) do q := q^.next; if Head = p then Head := p^.next q q Head p p nil Проблема: нужно знать адрес предыдущего узла q. особый случай: удаляем первый узел ищем узел, такой что q^.next = p Dispose(p); освобождение памяти

16 Алфавитно-частотный словарь Алгоритм: 1)открыть файл на чтение; 2)прочитать очередное слово (как?) 3)если файл закончился, то перейти к шагу 7; 4)если слово найдено, увеличить счетчик (поле count ); 5)если слова нет в списке, то создать новый узел, заполнить поля ( CreateNode ); найти узел, перед которым нужно вставить слово ( FindPlace ); добавить узел ( AddBefore ); 6)перейти к шагу 2; 7)закрыть файл 8)вывести список слов, используя проход по списку. var F: Text;... Assign(F, 'input.dat'); Reset ( F ); var F: Text;... Assign(F, 'input.dat'); Reset ( F ); Close ( F );

17 Как прочитать одно слово из файла? function GetWord : string; var c: char; begin Result := ''; { пустая строка } c := ' '; { пробел – чтобы войти в цикл } { пропускаем спецсимволы и пробелы } while not eof(f) and (c ' ') do begin Result := Result + c; read(F, c); end; function GetWord : string; var c: char; begin Result := ''; { пустая строка } c := ' '; { пробел – чтобы войти в цикл } { пропускаем спецсимволы и пробелы } while not eof(f) and (c ' ') do begin Result := Result + c; read(F, c); end; Алгоритм: 1)пропускаем все спецсимволы и пробелы (с кодами

18 Полная программа { глобальные переменные} type PNode = ^Node; Node = record... end; { новые типы данных } var Head: PNode; { адрес головы списка } NewNode, q: PNode; { вспомогательные указатели } w: string; { слово из файла } F: text; { файловая переменная } count: integer; { счетчик разных слов } { процедуры и функции пользователя} {процедура обработки щелчка по главной кнопке программы} procedure TForm1.Button1Click(Sender: TObject); begin Head := nil; AssignFile ( F, Edit1. Text ); Reset ( F ); { читаем слова из файла, строим список } CloseFile ( F ); { выводим список в другой файл } end. { глобальные переменные} type PNode = ^Node; Node = record... end; { новые типы данных } var Head: PNode; { адрес головы списка } NewNode, q: PNode; { вспомогательные указатели } w: string; { слово из файла } F: text; { файловая переменная } count: integer; { счетчик разных слов } { процедуры и функции пользователя} {процедура обработки щелчка по главной кнопке программы} procedure TForm1.Button1Click(Sender: TObject); begin Head := nil; AssignFile ( F, Edit1. Text ); Reset ( F ); { читаем слова из файла, строим список } CloseFile ( F ); { выводим список в другой файл } end.

19 Полная программа (II) { читаем слова из файла, строим список } while True do begin { бесконечный цикл } w := GetWord; { читаем слово } if w = '' then break; { слова закончились, выход } q := Find ( Head, w ); { ищем слово в списке } if q nil then { нашли, увеличить счетчик } q^.count := q^.count + 1 else begin { не нашли, добавить в список } NewNode := CreateNode ( w ); q := FindPlace ( Head, w ); AddBefore ( Head, q, NewNode ); end; { читаем слова из файла, строим список } while True do begin { бесконечный цикл } w := GetWord; { читаем слово } if w = '' then break; { слова закончились, выход } q := Find ( Head, w ); { ищем слово в списке } if q nil then { нашли, увеличить счетчик } q^.count := q^.count + 1 else begin { не нашли, добавить в список } NewNode := CreateNode ( w ); q := FindPlace ( Head, w ); AddBefore ( Head, q, NewNode ); end;

20 Полная программа (III) { выводим список в другой файл } q := Head; { проход с начала списка } count := 0; { обнулили счетчик слов } AssignFile(F, Edit2.Text); Rewrite(F); while q nil do begin { пока не конец списка } count := count + 1; { еще одно слово } writeln ( F, q^.word, ': ', q^.count ); q := q^.next; { перейти к следующему } end; Label1.Caption:='Найдено '+IntToStr(count)+ +' разных слов.'; CloseFile(F); Memo1.LoadFromFile.Lines(Edit2.Text); { выводим список в другой файл } q := Head; { проход с начала списка } count := 0; { обнулили счетчик слов } AssignFile(F, Edit2.Text); Rewrite(F); while q nil do begin { пока не конец списка } count := count + 1; { еще одно слово } writeln ( F, q^.word, ': ', q^.count ); q := q^.next; { перейти к следующему } end; Label1.Caption:='Найдено '+IntToStr(count)+ +' разных слов.'; CloseFile(F); Memo1.LoadFromFile.Lines(Edit2.Text);

type PNode = ^Node; { указатель на узел } Node = record { структура узла } word: string[40]; { слово } count: integer; { счетчик повторений } next: PNode; { ссылка на следующий } prev: PNode; { ссылка на предыдущий } end; type PNode = ^Node; { указатель на узел } Node = record { структура узла } word: string[40]; { слово } count: integer; { счетчик повторений } next: PNode; { ссылка на следующий } prev: PNode; { ссылка на предыдущий } end; 21 Двусвязные списки Структура узла: Адреса «головы» и «хвоста»: var Head, Tail: PNode;... Head := nil; Tail := nil; var Head, Tail: PNode;... Head := nil; Tail := nil; nextprev previous можно двигаться в обе стороны нужно работать с двумя указателями вместо одного nil Head Tail

22 Задания «4»: «Собрать» из этих функций программу для построения алфавитно-частотного словаря. В конце файла вывести общее количество разных слов (количество элементов списка). «5»: То же самое, но использовать двусвязные списки. «6»: То же самое, что и на «5», но вывести список слов в порядке убывания частоты, то есть, сначала те слова, которые встречаются чаще всего.