Скачать презентацию Тема 4 Списки и их программная реализация Ø Скачать презентацию Тема 4 Списки и их программная реализация Ø

Лекция_23_24_ДинамическиеСписки.ppt

  • Количество слайдов: 58

Тема 4 Списки и их программная реализация Ø Что такое список, стек, очередь Ø Тема 4 Списки и их программная реализация Ø Что такое список, стек, очередь Ø Организация работы со списками на основе динамических массивов Ø Понятие рекурсивных данных и однонаправленные списки Ø Начальное формирование, добавление и удаление элементов однонаправленного списка Ø Разновидности связанных списков 2/18/2018 1

Что такое список Ø В практике программирования довольно часто встречается задача обработки набора однотипных Что такое список Ø В практике программирования довольно часто встречается задача обработки набора однотипных данных Ø Inf 1, Inf 2, . . . Infn, Ø Ø количество которых n меняется в зависимости от ситуации Ø Их надо разместить в оперативной памяти и по мере надобности с ними работать: добавлять новые данные в список, освобождаться от старых данных, выдавать информацию о количестве данных, находить нужную информацию Ø Такой набор программисты называют СПИСКОМ 2/18/2018 2

Показательным примером является задача обслуживания очереди заказов на покупку товара Ø Inf 1, Inf Показательным примером является задача обслуживания очереди заказов на покупку товара Ø Inf 1, Inf 2, . . . Infn Ø Данные Infi могут содержать информацию о заказчике: Ø ФИО, адрес, финансовые возможности и др. Ø По мере появления новых заказчиков их дописывают в конец очереди (Infn+1, Infn+2, . . ), по мере поступления товара, и обслуживания заказчиков из начала очереди данные Inf 1, Inf 2, . . . об этих заказчиках стираются. Ø При решении подобных задач программисты вводят понятие списка 2/18/2018 3

Список (list) Ø Это последовательность однотипных элементов (данных), с которыми надо работать в оперативной Список (list) Ø Это последовательность однотипных элементов (данных), с которыми надо работать в оперативной памяти: добавлять новые элементы, удалять использованные, сортировать, находить нужные Ø Ø В процессе работы список может возрастать и уменьшаться Ø Ø Наибольшее распространение получили две формы работы со списком Ø – очередь Ø - стек. 2/18/2018 4

Очередь (turn) Ø это список с двумя точками входа. С одной стороны последовательности данные Очередь (turn) Ø это список с двумя точками входа. С одной стороны последовательности данные добавляются в список (в конец очереди), с другой стороны списка данные удаляются из него (из начала очереди) Ø Ø Таким образом реализуется принцип – «первым пришел – первым вышел» Ø Наглядный пример – трубка, заполняемая шариками, имеющими диаметр, равный диаметру трубки. С одной стороны трубки шарики добавляются в нее, с другой вынимаются. 2/18/2018 5

Стек (stek) Ø это список с одной точкой входа. Ø Данные добавляются в список Стек (stek) Ø это список с одной точкой входа. Ø Данные добавляются в список и удаляются из него только с одной стороны последовательности (вершины стека) Ø Таким образом реализуется принцип – «последний пришел – первым вышел» Ø Наглядный пример – трубка, запаянная с одного конца и заполняемая шариками, имеющими диаметр, равный диаметру трубки. С одной стороны трубки шарики добавляются в нее и вынимаются 2/18/2018 6

Организация работы со списками на основе динамических массивов Ø Простейшая форма организации списка – Организация работы со списками на основе динамических массивов Ø Простейшая форма организации списка – это динамический массив данных. Данные, размещенные в массиве имеют свои номера (индексы) и это придает эффект «видимости» каждому элементу. Ø a: a 1 a 2 a 3 a 4 ………. . an Ø Мы уже научились некоторым приемам работы с массивами и оценили их эффективность. Ø Рассмотрим как организуется работа со списками на основе динамического массива a переменного размера n. 2/18/2018 7

Класс для работы со списком на основе массива • type • Tinf = <тип Класс для работы со списком на основе массива • type • Tinf = <тип элементов>; • Tms=array[1. . 1] of Tinf; • Pms=^Тms; //указатель на массив • Tlist=Class(Tobject) • a, a 1: pms; n, mt: word; • constructor create; • procedure Addk(с: Tinf); //добавить • procedure Read 1(var с: Tinf); //удалить • procedure sort; • end; • • • 2/18/2018 constructor Tlist. create; begin Inherited create; n: =0; mt: = sizeof(Tinf); a: =Nil; end; 8

Работа с очередью • var turn: Tlist; с1, c 2: Tinf; • begin • Работа с очередью • var turn: Tlist; с1, c 2: Tinf; • begin • turn: =Tlist. create; //создадим новую очередь • //введем в нее сохраненный ранее список • Read(m); • • for i: =1 to m do begin Read(Fl, c 1); turn. Addk(c 1) end; . . . . //далее работаем с очередью: turn. Addk(c 1); //добавляем элементы. . turn. Read 1(c 2); //читаем и удаляем элементы. . turn. Free; //освобождаем память отсписка 2/18/2018 9

Метод Addk(c) Ø При реализации метода Addk добавления нового элемента в список необходимо Ø Метод Addk(c) Ø При реализации метода Addk добавления нового элемента в список необходимо Ø выделить память на 1 элемент большую, Ø Ø затем скопировать старый список в новый раздел памяти, Ø добавить в конец массива еще 1 элемент, после чего освободить ранее выделенную память и установить указатель a на новый раздел памяти: a: a 1: a 2 1 a 3 2 … 3 … an c n n+1 Dispose(a) a: =a 1 n: =n+1 2/18/2018 10

Программа Addk • procedure Tlist. Addk(c: Tinf); • begin • Get. Mem(a 1, (n+1)* Программа Addk • procedure Tlist. Addk(c: Tinf); • begin • Get. Mem(a 1, (n+1)* mt); • a 1[n+1]: =с; //добавление элемента • if n>0 then begin • for i: =1 to n do // копирование • a 1[i]: =a[i]; • Free. Mem(a, mt*n); //освобождение • end; • a: =a 1; n: =n+1; //теперь имя опять a • end; 2/18/2018 11

Метод Read 1(var c: Tinf) Ø При реализации метода Read 1 чтения и удаления Метод Read 1(var c: Tinf) Ø При реализации метода Read 1 чтения и удаления элемента из начала списка Ø Прочесть первый элемент списка в с Ø Выделить память на 1 элемент меньшую, Ø Ø Скопировать старый список начиная со второго в новый раздел памяти Ø освободить ранее выделенную память и установить указатель a на новый раздел памяти: c a: 2/18/2018 a 1: a 2 1 Dispose(a) a 3 2 … … n-1 an a: =a 1 n: =n-1 12

Программа Read 1 • procedure Tlist. Read 1(var c: Tinf); • begin • if Программа Read 1 • procedure Tlist. Read 1(var c: Tinf); • begin • if n>0 then begin • c: =a[1]; n: =n-1; • if n>0 then begin • Get. Mem(a 1, n* mt); • //копирование • for i: =1 to n do a 1[i]: =a[i+1]; • end else a 1: =nil; • Free. Mem(a, mt*(n+1)); //освобождение • a: =a 1; //теперь имя опять a • end else «список пуст!!!» ; • end; 2/18/2018 13

Резюме 1 Ø Удобство работы с динамическим массивом определяется тем, что в нем можно Резюме 1 Ø Удобство работы с динамическим массивом определяется тем, что в нем можно организовать эффективный двоичный поиск, организуя упорядоченность при добавлении нового элемента. Ø Легко написать методы Addi, Readi вставки и удаления массива по индексу Ø Применимы также эффективные методы сортировки Ø Эта простая схема хорошо работает для небольших списков, но у нее есть следующий существенный недостаток. Ø При каждом добавлении приходится менять размер выделенной памяти и, что еще хуже, копировать 2/18/2018 14

Резюме 2 Ø Иногда хороший выход из этой ситуации – организация изменения размера n Резюме 2 Ø Иногда хороший выход из этой ситуации – организация изменения размера n порциями (например по 20 элементов). Можно сделать размер порции зависимой от текущей длины массива (например 10% от n). Ø Процедура удаления i-го элемента тоже требует кроме выделения новой памяти и копирования еще и «схлопывания» , т. е. сдвига каждого элемента на одну позицию, чтобы заполнить освободившуюся i-го позицию. Ø Вместо удаления заданного элемента, чтобы избежать копирования, его можно пометить как неиспользуемый, поместив в ключ так называемое «мусорное» значение (например ключ=0), а при организации процедур обработки списка предусмотреть это. По мере накопления мусора в списке его надо собирать, что делается за один проход копирования. Ø Ø Все это, однако, требует дополнительных проверок и усложняет программы, однако это может окупаться удобством работы с массивом 2/18/2018 15

Понятие рекурсивных данных, косвенная адресация и однонаправленные списки Ø Мы видели, при организации работы Понятие рекурсивных данных, косвенная адресация и однонаправленные списки Ø Мы видели, при организации работы со списками на основе массивов они не обладают достаточной гибкостью. Например, при добавлении или удалении элементов в список требуется перестроить массив, сдвигая на одну позицию все элементы расположенные правее места вставки (удаления). Ø А можно ли организовать список таким образом, чтобы при добавлении и удалении из него элемента не требовалось дополнительных затрат на перестройку и при этом память использовалась рационально? Ø Ø Оказывается, такую организацию списка можно осуществить на основе рекурсивных типов данных, которые поддерживает Delphi. Ø Мы уже знакомы с понятием рекурсивной процедуры, которая при своем описании имеет обращение к самой себе. Ø Подобно этому рекурсивный тип данных при своем описании допускает обращение к самому себе. 2/18/2018 16

Программирование рекурсивного типа данных • Type • Tinf=record; // конкретизация типа данных, • • Программирование рекурсивного типа данных • Type • Tinf=record; // конкретизация типа данных, • • . . . // содержащихся в ячейках списка Key: Tkey; end; Tsel=^sel; //рекурсивный тип sel=Record Inf: TInf; // информация об элементе списка A: Tsel; //Адрес ячейки такого же типа end; • • • Var • sp, sp 1, spk: Tsel; //указатели на ячейки списка 2/18/2018 17

Структура рекурсивного типа данных Ø Здесь используется единственное исключение языка Паскаль – тип (sel) Структура рекурсивного типа данных Ø Здесь используется единственное исключение языка Паскаль – тип (sel) используется раньше, чем он описан Ø Ø Как видим, описание типа Tsel содержит внутри обращение к самому себе (A: Tsel), т. е. оно рекурсивно. Ø При этом А является указателем на ячейку памяти точно такой же структуры. Ø Ø В переменной Inf размещаются данные о некотором элементе списка, причем по крайней мере в одном из полей Inf, а иногда и в отдельном поле записи расположены сведения по которым производится поиск требуемой информации. Ø Ø Это поле будем обозначать key: Tkey, а сведения называть ключом. 2/18/2018 18

Описываемая типом Тsel ячейка spi+1 spi Inf, key A Inf, key nil ØЯчейки располагаются Описываемая типом Тsel ячейка spi+1 spi Inf, key A Inf, key nil ØЯчейки располагаются в куче. Под новую ячейку сначала находится свободное место в куче ØNew(sp) Øв ней помещается вся нужная информация sp. Inf: =Inf Øв адресной части ячейки помещают адрес следующей ячейки Ø A: =spi+1 или A: =nil ØПосле того как ячейка уже не нужна освобождается соответствующая память, 2/18/2018 ØDispose(sp) 19

однонаправленные (линейные) связанные списки sp 1 sp 2 I 1 A 1 I 2 однонаправленные (линейные) связанные списки sp 1 sp 2 I 1 A 1 I 2 A 2 …. spk-1 spk Ik-1 Ak-1 Ik nil Ø Реализуется косвенная адресация Ø Элементы списка размещаются в ячейках памяти типа Tsel, причем в указателе А каждой ячейки помещается адрес следующей за ней ячейки Ø Все ячейки динамически размещаются в куче по адресам sp 1, sp 2. . . spk. Ø Адрес начальной ячейки запоминается в указателе (например, в sp 1), Ø В адресной части последней ячейки записывается Nil (отсутствие адреса) 2/18/2018 20

Переход от одной записи к другой sp 2 sp 1 I 1 sp sp: Переход от одной записи к другой sp 2 sp 1 I 1 sp sp: =sp 1; A 1 sp 3 I 2 A 2 I 1 A 1 I 2 A 1 nil A 3 sp 3 I 2 A 2 I 4 nil //теперь в sp находится sp 2 sp 4 I 3 sp: =sp^. A; //теперь в sp находится sp 4 2/18/2018 I 4 sp 4 I 3 sp: =sp^. A; sp 2 I 1 A 3 sp sp 1 I 3 // текущий указатель установили в начало списка sp 2 sp 1 sp 4 A 3 I 4 nil sp 21

Переход от одной записи к другой sp 1 sp 2 I 1 A 1 Переход от одной записи к другой sp 1 sp 2 I 1 A 1 sp 3 I 2 A 2 sp 4 I 3 A 3 I 4 nil sp • • sp: =sp 1; // указатель установили в начало списка sp: =sp^. A; //теперь в sp находится sp 2 sp: =sp^. A; //теперь в sp находится sp 4 Write(sp^. Inf); //вывод информации Inf 4 • В обратную сторону передвигаться нельзя! • Поэтому список и называется однонаправленный. • Для многих практически важных задач такая организация списка оказывается эффективной 2/18/2018 22

Стек- список с одной точкой входа sp 1 I 1 A 1 I 2 Стек- список с одной точкой входа sp 1 I 1 A 1 I 2 A 2 …. Ik-1 Ak-1 Ik nil Ø Программисту известен только один указатель sp 1, который назовем вершиной стека Ø Доступ к ячейкам стека возможен только через этот указатель, в котором расположен адрес первой ячейки. sp 1 2/18/2018 23

Очередь- список с двумя точками входа sp 1 spk I 1 A 1 I Очередь- список с двумя точками входа sp 1 spk I 1 A 1 I 2 A 2 …. Ik-1 Ak-1 Ik nil Ø Программисту известны два указателя sp 1, spk Ø Доступ к ячейкам стека возможен только через эти указатели, в которых расположены адрес первой и адрес последней ячеек Ø В конец очереди через spk добавляют новые ячейки, из начала очереди через sp 1 удаляют ячейки. sp 1 2/18/2018 spk 24

Класс для работы со списком (задание типа ячеек) • Type • Tinf=record; // конкретизация Класс для работы со списком (задание типа ячеек) • Type • Tinf=record; // конкретизация типа данных, • • I 1: TI 1; I 2: TI 2; . . . // содержащихся в ячейках списка Key: Tkey; //ключ • end; • • Tsel=^sel; //рекурсивный тип sel=Record Inf: TInf; // информация об элементе списка A: Tsel; //Адрес ячейки такого же типа end; • 2/18/2018 25

Класс для работы со списком (поля и методы) • Type Tlist=class(Tobject) • sp 1, Класс для работы со списком (поля и методы) • Type Tlist=class(Tobject) • sp 1, spk, sp: psel; • constructor create; • procedure Add 1(Inf: Tinf); • procedure Addk(Inf: Tinf); • procedure Read 1(Inf: Tinf); • . . . • procedure Print; • end; • constructor Tlist. create; • begin • inherited create; • sp 1: =nil; spk: =nil; • end; 2/18/2018 26

Работа с методами класса • Var stec, st 1, turn, tr 1: Tlist; inf: Работа с методами класса • Var stec, st 1, turn, tr 1: Tlist; inf: Tinf; • Begin • stec: =Tlist. create; • stec. Add 1(inf); • . . . . • stec. print; • . . . . • stec. free; Ø Методы работы с очередью немного отличаются от методов работы со стеком – при работе с очередью необходимо поддерживать вторую точку входа spk Ø Поэтому более удобно написать два класса – один для работы со стеком, другой с очередью 2/18/2018 27

Класс для работы со стеком • Type Tlist. Stk=class(Tobject) • sp 1, sp: psel; Класс для работы со стеком • Type Tlist. Stk=class(Tobject) • sp 1, sp: psel; • constructor create; • procedure Add 1(Inf: Tinf); • procedure Read 1(Inf: Tinf); • . . . • procedure Print; • end; • constructor Tlist. Stk. create; • begin • inherited create; • sp 1: =nil; • end; 2/18/2018 28

Класс для работы с очередью • Type Tlist. Trn=class(Tobject) • sp 1, spk, sp: Класс для работы с очередью • Type Tlist. Trn=class(Tobject) • sp 1, spk, sp: psel; • constructor create; • procedure Add 1(Inf: Tinf); • procedure Addk(Inf: Tinf); • procedure Read 1(Inf: Tinf); • . . . • procedure Print; • end; • constructor Tlist. Trn. create; • begin • inherited create; • sp 1: =nil; spk: =nil; • end; 2/18/2018 29

Основные методы работы со стеком (класс Tlist. Stk) Ø Метод Add 1 – добавить Основные методы работы со стеком (класс Tlist. Stk) Ø Метод Add 1 – добавить элемент в стек Ø Метод Read 1 – взять элемент из стека Ø Метод Print – распечатать содержимое стека Ø Метод Add. Aftter – добавить элемент в стек после элемента с заданным адресом Ø Метод Add. Before – добавить элемент в стек перед элементом с заданным адресом Ø Метод Read. Aftter – взять из стека элемент расположенный после элемента с заданным адресом 2/18/2018 30

Add 1 - добавить в стек • Procedure Tlist. Stk. Add 1(Inf: TInf); • Add 1 - добавить в стек • Procedure Tlist. Stk. Add 1(Inf: TInf); • begin • New(sp); • sp^. Inf: =Inf; • sp^. A: =sp 1; • sp 1: =sp; • end; sp 1 New(sp) sp Inf 2/18/2018 sp 1 31

Read 1 – взять элемент из стека • Procedure Tlist. Stk. Reаd 1(var Inf: Read 1 – взять элемент из стека • Procedure Tlist. Stk. Reаd 1(var Inf: Tinf); • begin • Inf: =sp 1^. Inf; • sp: =sp 1; • sp 1: =sp 1^. A; • Dispose(sp); • end; Inf sp 1 sp 2/18/2018 sp 1 32

Print – распечатать содержимое стека • Procedure Tlist. Stk. Print(memo: Tmemo); • var k: Print – распечатать содержимое стека • Procedure Tlist. Stk. Print(memo: Tmemo); • var k: word; • begin • sp: =sp 1; k: =0; • While sp <> Nil do • begin k: =k+1; • Memo. Lines. Add(‘k=‘, Int. Tostr(k)); • Memo. Lines. Add(‘I 1=‘, sp^. Inf. I 1); • Memo. Lines. Add(‘key=‘, sp^. Inf. key); • sp: =sp^. A; • end; 2/18/2018 33

Add. Aftter – добавить элемент в стек после элемента с заданным адресом Procedure Tlist. Add. Aftter – добавить элемент в стек после элемента с заданным адресом Procedure Tlist. Stk. Add. After(spi: Tsel, Inf: TInf); • begin • New(sp); • sp^. Inf: =Inf; • sp^. A: =spi^. A; • spi^. A: =sp; • end; spi sp 1 sp 2/18/2018 Inf 34

Add. Before – добавить элемент в стек перед элементом с заданным адресом • Procedure Add. Before – добавить элемент в стек перед элементом с заданным адресом • Procedure • Tlist. Add. Before(spi: Psel; Inf: Tinf); • begin • Add. After(spi, spi^. Inf); spi^. Inf: =Inf; • end; Inf spi sp 1 2/18/2018 35

Read. Aftter – взять из стека элемент после элемента с заданным адресом • Procedure Read. Aftter – взять из стека элемент после элемента с заданным адресом • Procedure • Tlist. Read. After(spi: Tsel; var Inf: TInf); • begin • sp: =spi^. A; • Inf: =sp^. Inf; • spi^. A: =sp^. A; • Dispose(sp); • end; spi sp Inf sp 1 2/18/2018 36

Основные методы работы с очередью (класс Tlist. Trn) Ø Метод Addk – добавить элемент Основные методы работы с очередью (класс Tlist. Trn) Ø Метод Addk – добавить элемент в очередь Ø Метод Read 1 – взять элемент из очереди Ø Метод Readk – взять последний элемент из очереди 2/18/2018 37

Addk – добавить элемент в конец очереди • Procedure Tlist. Trn. Addk(Inf: TInf); • Addk – добавить элемент в конец очереди • Procedure Tlist. Trn. Addk(Inf: TInf); • begin • New(sp); • sp^. A: =Nil; • sp^. Inf: =inf; • if sp 1=Nil then begin • spk: =sp; sp 1: =sp; • end • else • begin spk^. A: =sp; spk: =sp; end; • end; sp 1 spk sp 1 I 1 A 1 …. Ik-1 Ak-1 Ik nil Inf nil sp 2/18/2018 38

Read 1 – взять первый элемент из очереди • Procedure Tlist. Trn. Reаd 1(var Read 1 – взять первый элемент из очереди • Procedure Tlist. Trn. Reаd 1(var Inf: Tinf); • begin • Inf: =sp 1^. Inf; • sp: =sp 1; • sp 1: =sp 1^. A; • if sp 1=Nil then spk: =Nil; • Dispose(sp); • end; Ø Этот метод отличается от аналогичного для стека только тем, что поддерживается вторая точка входа spk (оператор if). В некоторых случаях это делать необязательно. Ø Проверка того, пуста ли очередь перед выборкой элемента оставляется на усмотрение программиста 2/18/2018 39

Readk – взять последний элемент из очереди • Procedure Tlist. Trn. Reаdk(var Inf: Tinf); Readk – взять последний элемент из очереди • Procedure Tlist. Trn. Reаdk(var Inf: Tinf); • Begin Inf: =spk. Inf; if sp 1=spk then //если одна • begin Dispose(sp 1); sp 1: =Nil; spk: =Nil end • else begin • sp: =sp 1; //поиск предпоследней • while sp^. A<>Spk do sp: =sp^. A; • Dispose(spk); • spk: =sp; • spk^. A: =Nil; • end; sp 1 spk I 1 2/18/2018 A 1 …. Ik-1 Ak-1 Ik nil 40

Некоторые проблемы работы с однонаправленным списком Ø Как мы видели, в однонаправленном списке довольно Некоторые проблемы работы с однонаправленным списком Ø Как мы видели, в однонаправленном списке довольно сложно взять элемент изнутри списка Ø Например последний элемент из очереди просто так удалить не получается, хотя имеется его адрес spk Ø Так же проблематично вставить элемент внутрь очереди перед заданным Ø Хотя довольно эффективно работают процедуры удаления и вставки элемента после элемента с заданным адресом Read. Aftter, Add. Aftter. Ø Однако при их регулярном использовании имеется проблема первого элемента – его надо обрабатывать другой процедурой, а значит каждый раз требуется лишняя проверка Ø Чтобы избавиться от нее, часто используют Список с меткой 2/18/2018 41

Список с меткой sp 1 spk I A I 1 A 1 …. Ik-1 Список с меткой sp 1 spk I A I 1 A 1 …. Ik-1 Ak-1 Ik nil Ø В таком списке от первой ячейки используется только ее адресная часть sp 1. A, Ø в информационной же части могут быть при необходимости размещены данные об этом списке, при этом метка создается методом Add 1 Ø Stekm: =create; Stecm. add 1(Infm); . Ø При работе со стеком sp 1 остается неизменным Ø После создания списка с меткой работа с ним производится с помощью единообразных процедур Read. After, Add. After, Poisk. After. 2/18/2018 42

Циклические связанные списки sp 1 I 1 A 1 …. Ik-1 Ak-1 Ik sp Циклические связанные списки sp 1 I 1 A 1 …. Ik-1 Ak-1 Ik sp 1 Ø Циклические списки используются, когда нужно обходить набор элементов в бесконечном цикле. Ø Они так же позволяют получить доступ к списку начиная с любой позиции, что придает списку некоторую симметрию. Ø Программа может работать со всеми элементами одинаково без использования меток с помощью процедур Red. After, Add. After, Poisk. After. 2/18/2018 43

Обход циклического списка • Procedure Tlist. Stk. Printc(sp 1: Psel); • begin sp: =sp Обход циклического списка • Procedure Tlist. Stk. Printc(sp 1: Psel); • begin sp: =sp 1; • Repeat • Write(sp^. Inf); • sp: =sp^. A; • Until sp: =sp 1; • end; • Ø При работе с циклическим списком необходимо держать в памяти адрес одного из элементов sp 1 2/18/2018 . 44

Двухсвязные списки I sp 1 nil А 2 A 1 A 2 I spk Двухсвязные списки I sp 1 nil А 2 A 1 A 2 I spk I A 1 nil Ø организуются когда требуется просматривать список как в одном так и в обратном направлениях. Ø Мы видели, что в однонаправленном списке довольно просто удалить (вставить) новую ячейку после заданной, но довольно сложно удалить саму заданную ячейку или предыдущую к ней. Ø Эта проблема легко решается, если ввести рекурсивный тип с двумя адресными ячейками 2/18/2018 45

Рекурсивный тип с двумя адресными ячейками • Type • Tseld=^seld; • seld=record • Inf: Рекурсивный тип с двумя адресными ячейками • Type • Tseld=^seld; • seld=record • Inf: Tinf; • A 1: Tseld; • A 2: Tseld; • end; • Tlistd=class(Tobject) • sp 1, spk, sp: Tseld; • constructor create; • procedure add 1(inf: Tinf); • procedure readk(var inf: Tinf); • . . • end; 2/18/2018 46

Движение по списку I sp 1 nil • • • А 2 A 1 Движение по списку I sp 1 nil • • • А 2 A 1 A 2 I spk I A 1 nil движение вправо Write(sp 1. A 2. inf); sp: =sp 1. A 2; движение влево Write(spk. A 1. inf); sp: =spk. A 1; 2/18/2018 47

Добавление элемента в начало • Procedure Tlistd. add 1(Inf: Tinf); • begin • if Добавление элемента в начало • Procedure Tlistd. add 1(Inf: Tinf); • begin • if sp 1=nil then • begin New(sp 1); • sp 1^. inf: =inf; • Sp 1^. A 1: =nil; • sp 1^. A 2: =nil; • spk: =sp 1 end • else begin • New(sp); • sp^. A 1: =Nil; sp^. A 2: =sp 1; • sp^. inf: =inf; sp 1^. A 1: =sp; • sp 1: =sp; end; • end; I sp 1 nil 2/18/2018 sp А 2 A 1 A 2 I spk I A 1 nil A 2 I 48

Добавление в начало Inf spk I sp 1 nil А 2 A 1 A Добавление в начало Inf spk I sp 1 nil А 2 A 1 A 2 I spk I A 1 nil A 1 A 2 I sp nil 2/18/2018 Если список был пуст Inf 49

чтение последнего элемента • Procedure Tlistd. readk(var Inf: Tinf); • begin • sp: =spk; чтение последнего элемента • Procedure Tlistd. readk(var Inf: Tinf); • begin • sp: =spk; inf: =sp^. inf; • sp^. A 1^. A 2: =Nil; • spk: =sp^. A 1; • dispose(sp); • end; Ø Аналогично составляются методы добавления элемента в конец списка и удаления начального элемента 2/18/2018 50

Чтение и удаление последнего nil I sp 1 nil А 2 A 1 A Чтение и удаление последнего nil I sp 1 nil А 2 A 1 A 2 I Inf spk I A 1 nil sp 2/18/2018 51

Добавление элемента после заданного в двухсвязный список • Procedure • Tlistd. Add. After(Inf: TInf; Добавление элемента после заданного в двухсвязный список • Procedure • Tlistd. Add. After(Inf: TInf; spi: Tseld); • begin • New(sp); • sp^. Inf: =Inf; • sp^. A 1: =spi; • sp^. A 2: =spi. A 2; • spi^. A 2: =sp; • sp^. A 2^. A 1: =sp; • end; 2/18/2018 52

Добавление после заданного I sp 1 nil А 2 spi sp spk I A Добавление после заданного I sp 1 nil А 2 spi sp spk I A 1 A 2 I A 1 nil A 1 A 2 I Inf 2/18/2018 53

Добавление элемента перед заданным • • • 2/18/2018 Procedure Tlistd. Add. Beford(Inf: TInf; spi: Добавление элемента перед заданным • • • 2/18/2018 Procedure Tlistd. Add. Beford(Inf: TInf; spi: Tseld); begin New(sp); sp^. Inf: =Inf; sp^. A 2: =spi; sp^. A 1: =spi. A 1; Spi^. A 1: =sp; sp^. A 1^. A 2: =sp; end; 54

Чтение и удаление элемента с адресом spi • Procedure • Tlistd. Read(var Inf: TInf; Чтение и удаление элемента с адресом spi • Procedure • Tlistd. Read(var Inf: TInf; spi: Pseld); • begin • Inf: =spi^. Inf; • spi^. A 1^. A 2: =spi^. A 2; • spi^. A 2^. A 1: =spi^. A 1; • Dispose(spi); • end; I sp 1 nil 2/18/2018 A 1 A 2 I А 2 spi spk I A 1 nil 55

Контрольные вопросы Ø Ø Ø Ø Что такое список, очередь, стек, для чего они Контрольные вопросы Ø Ø Ø Ø Что такое список, очередь, стек, для чего они нужны? Как организовать работу со списком на основе динамического массива? Напишите рекурсивный тип данных и объясните, как с его помощью организуется однонаправленный список. Что такое косвенная адресация? Опишите класс для работы со списком. Поясните особенности работы со стеком и очередью. Напишите метод распечатки списка. Как организуется список с меткой и когда его целесообразно использовать? Понятие циклического списка. 2/18/2018 56

Задача на экзамен Ø o o o Составить программу работы со списком на основе Задача на экзамен Ø o o o Составить программу работы со списком на основе одномерного динамического массива. Фамилию a. f и учетный номер a. k добавляемой записи читать из первой строки String. Grid 1. Состояние текущего списка из n записей отражать в n строках String. Grid 2. Учетный номер удаляемой записи ввести из Edit 1. В отдельном модуле написать класс, содержащий следующие методы: создание начального динамического массива Create; добавление новой записи в конец списка Аddk; Чтение с удалением записи из начала списка Read 1. 2/18/2018 57

Конец темы • Ваши вопросы 2/18/2018 58 Конец темы • Ваши вопросы 2/18/2018 58