1_Динамические структуры данных_Начало_линейные списки.ppt
- Количество слайдов: 57
ДИНАМИЧЕСКИЕ СТРУКТУРЫ ДАННЫХ
Динамическая переменная Объем памяти до начала работы программы не известен, т. е. фиксированный объем памяти выделен только под хранение адреса переменной. ¡ Значение переменной хранится в области хипа (динамической памяти) ¡
Указатель это переменная, хранящая адрес области памяти, в которой находится конкретное значение переменной. ¡ Можно хранить адрес данных или программного кода (например, адрес точки входа в процедуру). ¡ Адрес состоит из двух машинных слов: сегмент + смещение ¡
Объявление указателя Type имя_типа=^тип; Var имя_перем: тип; имя_перем: ^тип; Пример: Type pword=^word; Var pw: pword; pw 1: ^ word;
Выделение места для хранения значения переменной А) процедура new(имя указателя) Выделяет место и адрес начала участка заносит в указатель; Б) функция new(тип указателя); Выделяет место и адрес начала участка возвращает в указатель; С) процедура getmem(указатель, размер в байтах) Выделяет место размером в N байт и адрес начала участка заносит в указатель; Если требуемый объем памяти выделить не удалось происходит аварийное завершение работы программы.
Обращение к значению динамической переменной (разадресация) Имя_перем^ Пример: Var pw: ^ word; Begin new(pw); Pw^: =2; Inc(pw^); Write(pw^); End.
Виды указателей: 1. 2. Стандартные – могут хранить адреса переменных любого типа Var P: Pointer; Типизированные - можно хранить только адреса величин указанного типа (любой тип, кроме файлового) Var P: ^integer;
Операции с указателями ¡ Nil ¡ Сравнение if p 1=p 2 then … if p 1<>nil then… 1
Операции с указателями ¡ Стандартные функции: addr(x): pointer –возвращает адрес х - возвращает адрес сегмента х Ofs(x): word - возвращает смещение для х Seg(x): word Cseg: word - возвращает значение регистра сегмента кода CS Dseg: word - возвращает значение регистра сегмента данных DS Ptr(seg, ofs: word): pointer – по заданному сегменту и смещению формирует адрес типа pointer 2
Пример работы с динамическими переменными Type rec = record D: word; S: string; End; Pword = ^word; Var p 1, p 2: pword; p 3: ^rec;
Динамическая память p 1 Сегмент данных p 2 p 3
Пример работы с динамическими переменными Begin new(p 1); p 2: = new(pword); new(p 3); P 1^: =2; P 2^: =4; P 3^. d: =p 1^; P 3^. s: =‘Вася’;
2 p 1: ^ p 1 2 p 2: ^ p 2 2 Вася p 3
Пример работы с динамическими переменными Inc(p 1^); P 2^: =p 1^+p 3^. d; With p 3^ do writeln(d, s); Какие значения?
Пример работы с динамическими переменными p 1: =p 2; 4 p 1 Появление «цифрового мусора» !!! 4 p 2 P 2^ P 1^
Освобождение памяти 1) 2) 3) 4) Dispose (var p: pointer) Freemem(var p: pointer; size: word) Mark(var p: pointer) Release(var p: pointer) По завершению программы память освобождается автоматически.
Вспомогательные функции Maxavail: longint ¡ Memavail: longint ¡ Sizeof(x): word; ¡
1 Вспомогательные функции (пример) Program demo_memo; Type mas_int=array[1. . maxint] of integer; Var p: ^mas_int; I, n; integer;
2 Вспомогательные функции (пример) Begin writeln (‘ Введите размер массива’); Readln(n); If maxavail < n*sizeof(intrger) then Begin writeln (‘ Недостаточно памяти’); Halt end; Getmem(p, n*sizeof(integer)); For i: =1 to n do read( p^[i]); ………. End.
Указатели на процедуры и функции
Динамические структуры данных 1. 2. 3. 4. Линейный список Стек Очередь Дерево
Линейные списки
Списком называется структура данных, каждый элемент которой посредством указателя связывается со следующим элементом. Из определения следует: ¡ каждый элемент списка содержит поле данных (Data) (оно может иметь сложную структуру) ¡ Также каждый элемент списка содержит поле ссылки на следующий элемент (Next) ¡ поле ссылки последнего элемента должно содержать пустой указатель (NIL).
Nil u U^. Next ? ? ? U^. Data
Создание списка
Пример: Сформировать список, содержащий целые числа 3, 5, 1, 9. Решение Определим запись типа s с полями, содержащими характеристики данных — значения очередного элемента и адреса следующего за ним элемента. Type EXS =^S; S=Record Data: Integer; Next: EXS; End;
Получаем связанный однонаправленный список Nil u 3 5 1 9
Чтобы список существовал, надо определить указатель на его начало: Var u, x: EXS;
Создание первого элемента: New(u); {выделим место в памяти для переменной типа S} u^. next: =nil; {указатель пуст} u^. data: =3; {информационное поле первого элемента} Nil u U^. Next 3 U^. Data
Продолжим формирование списка. Для этого нужно добавить элемент в конец списка. х: =u; {введем вспомогательную переменную указательного типа, которая будет хранить адрес последнего элемента списка. Сейчас последний элемент списка совпадает с его началом} u Nil 3 x U^. Next U^. Data Т. е. , к области памяти можно обратиться через два указателя.
{выделим область памяти для следующего элемента cписка } New(x^. Next); u 3 x
{переменная х принимает значение адреса выделенной области памяти} x: =x^. Next; u 3 x
{определим значение этого элемента списка} x^. Data: =5; x^. Next: =Nil; Nil u 3 x 5
Procedure Init(Var u: Exs); {создание списка} Var x, у: Exs; Digit: Integer; {значение информационной части элемента Begin списка} Writeln(' Введите список '); u: = Nil; {список пуст} Write. Ln('Bведитe элементы списка. Конец ввода 0’); Read( Digit); While Digit<>0 Do Begin New(y); {формирование элемента списка} y^. Next: =Nil; Y^. Data: =Digit; If u=nil Then u: =y {вставляем первый элемент списка} Else x^. Next: =y; {вставляем элемент в конец списка} x: =у; {переносим значение указателя на последний элемент Read(Digit); End; Writeln; End; списка}
Т. е. мы построили список добавлением элементов в конец списка. Nil u 3 5 1 9 Новая задача: вставить элемент в начало списка Nil u 7 3 5 1 9
{создание новой динамической переменной} New(x); Nil u 3 5 1 9 x
x^. data: =7; {информационное поле созданного элемента} x^. next: =u; {присоединим элементы списка u к созданному элементу} Nil u 3 5 1 9 x 7
u: =x; {изменим значение указателя начала списка} Nil u 3 5 1 9 x 7
Просмотр списка
Просмотр списка Просмотр элементов списка осуществляется последовательно, начиная с его начала. Указатель р последовательно ссылается на первый, второй и т. д. элементы списка до тех пор, пока весь список не будет пройден. При этом с каждым элементом списка выполняется операция Ор (некоторая Операция p). Начальное значение p - адрес первого элемента списка р^ While {p указывает не на конец списка} Do Begin {выполнить с элементам р^ операцию Ор; перейти к следующему элементу} End;
Пусть Ор(р^) — это вывод элемента р^ на экран. Если р указывает на конец списка, то его значение равно NIL, то есть: While p<>Nil Do Begin Write(p^, ‘ ’); p: =р^. Next; End;
Пример: Сформировать список целых чисел упорядоченный по неубыванию. После ввода очередного числа с клавиатуры определяем его место в списке. При этом элемент может быть вставлен либо в начало списка, либо в конец его, либо во внутрь. Для того чтобы вставить в список элемент со значением Digit между двумя элементами, нужно найти элементы и запомнить их адреса (первый адрес — в переменной dx, второй — в рх), после чего установить новые связи с переменной, в которой хранится значение Digit.
Графически это можно представить так: dx px x Digit
Процедура Inshito, вставляющая в список элемент, переданный ей как параметр. Procedure Insinto(Digit: Integer; Var u: Exs); {вставка заданного элемента в список} Var dx, px, x: Exs; Begin New(x); x^. data: =Digit; x^. next: =NIL; {если список пуст, то вставляется первый элемент} If (u=Nil) Then u: =x Else {если список не пуст, то просматриваем его до тех пор, пока не отыщется подходящее место для х^ или не закончится список} Begin dx: =u; рх: =u; While (px<>Nil) And (px^. data<=Digit) Do Begin dx: =px; px: =px^. next; End; If px=Nil {пройден весь список} Then dx^. next: =x {элемент добавляется в конец списка} Else {пройден не весь список} Begin X^. next: =px; If px=u Then u: =x {вставляем в начало списка} Else dx^. next: =x; {вставляем внутрь списка} End;
Процедура Inshito, вставляющая в список элемент, переданный ей как параметр (продолжение) Begin {основная программа} u: =NIL; {список пуст} Writeln (‘ Введите элемент. Окончание ввода 0'); Read(Digit); While Digit<>0 Do Begin Insin. To(Digit, u); Read(Digit); End; Writeln ('cnucoк: '); Print(u); End.
Удаление элементов из списка
Пример: Удалить из заданного списка все вхождения элемента с заданным значением информационной части. . Обозначим u— исходный список, Digit — значение информационной части удаляемого элемента. Удалить элемент можно из любого места списка.
Удаление элемента из начала списка x u
Фрагмент программы х: =u; {запомним адрес первого элемента списка} u: =u^. next; Dispose(x); {теперь u указывает на второй элемент списка} {освободим память, занятую переменной x^)
Удаление элемента из середины списка dx u x
Фрагмент программы Нужно знать адреса удаляемого элемента и элемента, находящегося в списке перед ним. х: =u; {переменная х для хранения адреса удаляемого элемента} {найдем адреса нужных элементов списка } While (x<>Nil) And (x^. Data<>Digit) Do Begin dx: =x; х: =х^. Next End; Dx^. Next: =x^. Next; Dispose(x);
Удаление элемента из конца списка Производится, когда указатель dx показывает на предпоследний элемент списка, а х — на последний. {найдем предпоследний элемент} х: =u; dx: =u; While x^. Next<>NIL Do Begin dx: =x; x: =x^. Next; End; {удаляем элемент х^ из списка и освобождаем занимаемую им память} dx^. Next: = Nil; Dispose(x);
Процедура удаления элемента из списка Procedure Del(Digit: Integer; Var u: Exs); Var x, dx: Exs; Begin x: =u; While x<>Nil Do If x^. Data=digit Then Begin If x=u Then Begin u: =u^. Next; Dispose(x); х: =u End Else Begin dx ^. Next: =x^. Next; Dispose(x); x: =dx^. Next; End Else Begin dx: =x; x: =x^. Next; End;
Процедура удаления элемента из списка (продолжение) Procedure Del(Digit: Integer; Var u: Exs); Var x, dx: Exs; Begin x: =u; While x<>Nil Do If x^. Data=digit Then Begin If x=u Then Begin u: =u^. Next; Dispose(x);
Основная программа Begin Init(u); {формирование списка} Print(u ); {вывод списка} Write('Bведи число: '); Readln(Digit); Del(Digit, u); Print(u) End.
Задание 1 Прорисовать изменение значений переменной и при удалении из списка, изображенного на рисунке элементов со значением информационной части, равной 1 и 9. Nil u 3 5 1 9
Задание 2 N человек располагаются по кругу. Начав отсчет от первого, удаляют каждого k-го, смыкая при этом круг. Определить порядок удаления людей из круга. Для хранения данных об участниках игры используется список. u
1_Динамические структуры данных_Начало_линейные списки.ppt