62
Линейные структуры данных Федор Царев Спецкурс «Олимпиадное программирование» Лекция 1 01.12.2008, 08.12.2008 Санкт-Петербург, Гимназия 261

01 линейные структуры данных

Embed Size (px)

DESCRIPTION

Слайды лекции спецкурса "Олимпиадное программирование"

Citation preview

Page 1: 01 линейные структуры данных

Линейные структуры данных

Федор ЦаревСпецкурс «Олимпиадное

программирование»Лекция 1

01.12.2008, 08.12.2008Санкт-Петербург, Гимназия 261

Page 2: 01 линейные структуры данных

Цель лекции

Изучить теоретические основы линейных структур данных

Изучить методы их реализации на языке программирования Pascal (Delphi)

Page 3: 01 линейные структуры данных

Структуры данных

Алгоритмы + структуры данных = программы (Никлаус Вирт)

Способ организации хранения данных Набор операций и их свойства

Page 4: 01 линейные структуры данных

Линейные структуры данных

Наиболее просты для понимания Не содержат разветвлений Являются базовыми и используются во

многих алгоритмах и более сложных структурах данных

Список, стек, очередь, дек, …

Page 5: 01 линейные структуры данных

Тип «запись»

Служит для описания сущности, которая характеризуется несколькими параметрами

type student = recordname : string;class : integer;marks : array[1..10] of integer;

end;

Page 6: 01 линейные структуры данных

Поля записи

Запись – набор полей

vars : student;

s.name := ‘Vasya’;writeln(s.name);

Page 7: 01 линейные структуры данных

Указатели в языке Pascal

Указатель = адрес в памяти компьютера Выделение (new) и освобождение (delete)

памяти Тип данных «указатель на» pstudent = ^student

Page 8: 01 линейные структуры данных

Односвязный список Состоит из элементов (узлов) Данные и указатель на следующий узелtypepnode = ^node;node = recorddata : integer;next : pnode;

end; Указатель на начало списка first

firstData

Next

Data

Next

Data

Next

NIL

Page 9: 01 линейные структуры данных

Операции со списком

Добавление элемента (add) Поиск элемента (find) Удаление элемента (remove)

Page 10: 01 линейные структуры данных

Добавление элемента

firstData

Next

Data

NextNIL

Data

Next

first

Data

Next

Data

NextNIL

Data

Next

До добавления

После добавления

Page 11: 01 линейные структуры данных

Добавление элемента – программа

procedure add(x : longint);varp : pnode;

beginnew(p);p^.data := x;p^.next := first;first := p;

end;

Page 12: 01 линейные структуры данных

Поиск элементаfunction find(x : integer) : boolean;varwp : pnode;

beginwp := first;while (wp <> nil) do begin

if (wp^.data = x) then beginresult := true;exit;

end;wp := wp^.next;

end;result := false;

end;

Page 13: 01 линейные структуры данных

Удаление элемента

Элемент необходимо найти и удалить

firstData

Next

Data

Next

Data

Next

NIL

До удаления

После удаления

firstData

Next

Data

Next

Data

Next

NIL

Page 14: 01 линейные структуры данных

Удаление элемента

Два случая удаление первого элемента удаление не первого элемента

Необходимо знать не только удаляемый элемент, но и предыдущий

Page 15: 01 линейные структуры данных

Программа (начало)

procedure remove(x : integer);varcur, prev, tmp : pnode;

beginif (first = nil) then begin

exit;end;if (first^.data = x) then begin

tmp := first;first := first^.next;delete(tmp);exit;

end;

Page 16: 01 линейные структуры данных

Программа (продолжение)

prev := first;cur := first^.next;while (cur <> nil) do begin

if (cur^.data = x) then beginprev^.next := cur^.next;delete(cur);exit;

end;cur := cur^.next;prev := prev^.next;

end;end;

Page 17: 01 линейные структуры данных

Время работы операций с односвязным списком

add – O(1) – константное время find – O(n) – линейно зависит от числа

элементов в списке remove – O(n)

Page 18: 01 линейные структуры данных

Двусвязный список В каждом элементе хранится указатель не

только на следующий, но и на предыдущийtypepnode = ^node;node = recorddata : integer;next, prev : pnode;

end;

NILfirst

next

data

prev

next

data

prev

next

data

prev

Page 19: 01 линейные структуры данных

Операции с двусвязным списком

Добавление элемента (add) Поиск элемента (find) Удаление элемента (remove)

Page 20: 01 линейные структуры данных

Добавление элемента – программаprocedure add(x : longint);varp : pnode;

beginnew(p);p^.data := x;p^.next := first;if (first <> nil) then begin

first^.prev := p;end;first := p;

end;

Page 21: 01 линейные структуры данных

Поиск элемента Так же, как для односвязногоfunction find(x : integer) : boolean;varwp : pnode;

beginwp := first;while (wp <> nil) do begin

if (wp^.data = x) then beginresult := true;exit;

end;wp := wp^.next;

end;end;

Page 22: 01 линейные структуры данных

Удаление элемента

NILfirst

next

data

prev

next

data

prev

next

data

prev

NILfirst

next

data

prev

next

data

prev

next

data

prev

До удаления

После удаления

Page 23: 01 линейные структуры данных

Четыре случая

Нет ни предыдущего, ни следующего Есть только предыдущий Есть только следующий Есть и предыдущий, и следующий

Page 24: 01 линейные структуры данных

Удаление элемента – программа (начало)

procedure remove(x : integer);

var

cur, prev, next : pnode;

begin

if (first = nil) then begin

exit;

end;

end;

Page 25: 01 линейные структуры данных

Удаление элемента – программа (продолжение)cur := first;while (cur <> nil) do begin

if (cur^.data = x) then beginprev := cur^.prev;next := cur^.next;// Обработка 4 случаев:// следующие два слайдаexit;

end;cur := cur^.next;

end;

Page 26: 01 линейные структуры данных

Удаление элемента – обработка случаев (1, 2)if (prev=nil) and (next=nil) then begin// Элемент в списке одинfirst := nil;delete(cur);

end;if (prev <> nil) and (next = nil) thenbegin// Удаляется последний в списке элементprev^.next := nil;delete(cur);

end;

Page 27: 01 линейные структуры данных

Удаление элемента – обработка случаев (3, 4)if (prev=nil) and (next<>nil) thenbegin// Удаляется первый в списке элементfirst := next;delete(cur);

end;if (prev<>nil) and (next<>nil) then begin// Общий случайprev^.next := next;next^.prev := prev;delete(cur);

end;

Page 28: 01 линейные структуры данных

Запутались в случаях?

Используйте сторожевые элементы (sentinel elements) – специальные элементы, которые всегда присутствуют в списке, но не хранят никакой информации

Необходимо два таких элемента – в начале и в конце списка

Page 29: 01 линейные структуры данных

Список со сторожевыми элементамиtypepnode = ^node;node = recorddata : integer;next, prev : pnode;isSentinel : boolean;

end;

NIL

first

next

data

prev

next

data

prev

next

prev

next

prev

Page 30: 01 линейные структуры данных

Пустой список со сторожевыми элементами

NIL

first

next

prev

next

prev

Page 31: 01 линейные структуры данных

Добавление в списокprocedure add(x : longint);varp : pnode;

beginnew(p);p^.data := x;p^.next := first;first^.prev := p;first := p;

end;

Page 32: 01 линейные структуры данных

Поискfunction find(x : integer) : boolean;varwp : pnode;

beginwp := first;while (wp <> nil) do begin

if ( (not (wp^.isSentinel)) and (wp^.data = x) ) then begin

result := true;exit;

end;wp := wp^.next;

end;result := false;

end;

Page 33: 01 линейные структуры данных

Удаление элементаprocedure remove(x : integer);varcur, prev, next : pnode;

begincur := first;while (cur <> nil) do begin

if ( (not (cur^.isSentinel)) and (cur^.data = x) ) then begin

cur^.prev^.next := cur^.next;cur^.next^.prev := cur^.prev;delete(cur);exit;

end;cur := cur^.next;

end;end;

Вместо четырех случаев – один!

Page 34: 01 линейные структуры данных

Время работы операций с двусвязным списком

add – O(1) – константное время find – O(n) – линейно зависит от числа

элементов в списке remove – O(n)

Page 35: 01 линейные структуры данных

Стек

Stack Принцип LIFO (Last In

– First Out) Используется в

алгоритме обхода графа в глубину и при реализации рекурсии

Page 36: 01 линейные структуры данных

Операции со стеком

push(x) – положить элемент в стек pop() – взять элемент с верхушки стека isEmpty() – пуст ли стек

Page 37: 01 линейные структуры данных

Хранение стека в виде массива

top

1 2 3 4 5 6 7 8

Массив stack элементов, хранящихся в стеке Переменная top, хранящая номер верхнего

элемента

Page 38: 01 линейные структуры данных

Программная реализацияprocedure push(x : integer);begininc(top);stack[top] := x;

end;function isEmpty() : boolean;beginresult := (top = 0);

end;

Page 39: 01 линейные структуры данных

Программная реализация

function pop() : integer;beginif (isEmpty()) then begin

// Ошибка – извлекаем из // пустого стекаexit;

end;result := stack[top];dec(top);

end;

Page 40: 01 линейные структуры данных

Очередь

Queue Принцип FIFO (First In – First Out) Используется в алгоритме обхода графа в

ширину

Page 41: 01 линейные структуры данных

Операции с очередью

add – добавить элемент remove – извлечь элемент isEmpty – проверить пустоту

Page 42: 01 линейные структуры данных

Хранение очереди в виде массива

tail

1 2 3 4 5 6 7 8

head

Массив queue элементов, которые хранятся в очереди head – номер первого элемента массива, который

принадлежит очереди tail – номер элемента, следующего за последним в

очереди Элементы добавляются в хвост, извлекаются из головы

Page 43: 01 линейные структуры данных

Программная реализация

procedure add(x : integer);beginqueue[tail] := x;inc(tail);

end;

function isEmpty() : boolean;beginresult := (head = tail);

end;

Page 44: 01 линейные структуры данных

Программная реализация

function remove() : boolean;beginif (isEmpty()) then begin

// Ошибка – извлекаем из // пустой очередиexit;

end;result := queue[head];inc(head);

end;

Page 45: 01 линейные структуры данных

Дек

Dequeue = double-ended queue – очередь с двумя концами

Page 46: 01 линейные структуры данных

Операции с деком

addLeft – добавить слева removeLeft – извлечь слева addRight – добавить справа removeRight – извлечь справа isEmpty – проверить пустоту

Page 47: 01 линейные структуры данных

Представление дека в виде массива

right

1 2 3 4 5 6 7 8

left

Массив, хранящий элементы дека left – левая граница дека right – правая граница дека Надо быть аккуратным с границами массива, когда дек

пуст Можно объявить массив dequeue: array[-10..10] of longint;

Page 48: 01 линейные структуры данных

Программная реализация

function isEmpty() : boolean;beginresult := left > right;

end;

procedure addRight(x : integer);begininc(right);dequeue[right] := x;

end;

Page 49: 01 линейные структуры данных

Программная реализация

procedure addLeft(x : integer);begindec(left);dequeue[left] := x;

end;

Page 50: 01 линейные структуры данных

Программная реализация

function removeLeft() : boolean;beginif (isEmpty()) then begin

// Ошибка – извлекаем из // пустого декаexit;

end;result := dequeue[left];inc(left);

end;

Page 51: 01 линейные структуры данных

Программная реализация

function removeRight() : boolean;beginif (isEmpty()) then begin

// Ошибка – извлекаем из // пустого декаexit;

end;result := dequeue[right];dec(right);

end;

Page 52: 01 линейные структуры данных

Упражнение

Реализовать стек, дек и очередь на базе списков, а не на базе массивов

Page 53: 01 линейные структуры данных

Собственный менеджер памяти

Использовать указатели не всегда удобно Выделение и освобождение памяти –

достаточно медленные операции (порядка 100 тысяч операций в секунду, других операций можно совершить до 50 миллионов)

Можно написать свой менеджер памяти!

Page 54: 01 линейные структуры данных

Менеджер памяти Вместо памяти – массив memory : array[1..MAXMEM] of node; MAXMEM – «размер памяти» free – номер первой свободной ячейки Вместо указателей – номера ячеек массива

memory -1 ↔ nil 1 2 3 4 5 6 7 8

free

Page 55: 01 линейные структуры данных

Односвязный список

first234

Next

345

Next

567

Next

NIL

234

1

345

3

567

-1

first = 2free = 4

1 2 3 4 5 6

Page 56: 01 линейные структуры данных

Добавление в список

procedure add(x : longint);varp : integer;

beginp := free;inc(free);memory[p].data := x;memory[p].next := first;first := p;

end;

Page 57: 01 линейные структуры данных

Поиск элементаfunction find(x : integer) : boolean;varwp : integer;

beginwp := first;while (wp <> -1) do begin

if (memory[wp].data = x) then beginresult := true;exit;

end;wp := memory[wp].next;

end;result := false;

end;

Page 58: 01 линейные структуры данных

Удаление элемента (начало)

procedure remove(x : integer);varcur, prev, tmp : integer;

beginif (first = -1) then begin

exit;end;if (memory[first].data = x) then begin

tmp := first;first := memory[first].next;exit;

end;

Page 59: 01 линейные структуры данных

Удаление элемента (продолжение)prev := first;cur := memory[first].next;while (cur <> -1) do begin

if (memory[cur].data = x) then beginmemory[prev].next :=

memory[cur].next;exit;

end;cur := memory[cur].next;prev := memory[prev].next;

end;end;

Page 60: 01 линейные структуры данных

Упражнение

Реализовать двусвязный список на собственном менеджере памяти

Page 61: 01 линейные структуры данных

Выводы

Односвязный и двусвязный списки основаны на указателях

Для их реализации можно использовать как встроенный менеджер памяти (new, delete), так и собственный

Стек, очередь и дек можно реализовать на основе списков и массивов

Я рекомендую использовать свой менеджер памяти и реализацию стека, очереди и дека на базе массива

Page 62: 01 линейные структуры данных

Спасибо за внимание!

Вопросы? Комментарии?

[email protected]