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

advertisement
Алгоритмизация и
программирование
Структуры данных
10 класс
по учебнику Калинина И.А. и Самылкиной Н.Н.
ProPowerPoint.Ru
Структуры
данных
Списки
ProPowerPoint.Ru
Деревья
Основные элементы при
построении
Указатель
• Адрес
области
памяти, в которой
лежат данные.
• Если обговорено,
какие это данные,
указатель может
быть использован
для доступа к ним.
ProPowerPoint.Ru
Структурированный
набор
• На языке Pascal –
записи (record)
• Аналог массива,
состоящий из
переменных
разного типа.
Пример структуры
• Массив – индексированный набор
элементарных переменных.
• Массив представляет собой структуру,
в которую входит один тип
переменных.
ProPowerPoint.Ru
Хранение данных в
структурах
Статический тип
• Место для всех данных отводится сразу (чаще – в начале
блока), во время программы не изменяется.
• Используется при объявлении переменных.
Динамический тип
• Количество элементов заранее неизвестно, меняется во
время исполнения программы.
• Память отводится и освобождается самой программой.
ProPowerPoint.Ru
Динамические структуры
•
•
Требуют дополнительных операций!
Компилятор не всегда может проконтролировать правильность
выполнения!
• Список — динамическая структура данных, в которой каждый
элемент состоит из указателя на следующий элемент и
одинакового для всех элементов набора дополнительных
данных.
Место элемента в последовательности определяется не номером,
а указателем на него в предыдущем или в следующем по порядку
элементе, т. е. частью структуры. Список хранят как вход в него, т.
е. указатель на «голову» списка. Если указатель на «голову» пуст, то
и список пуст.
• Дерево - динамическая структура данных, которая имеет
минимум два возможных выхода из каждого элемента и не
имеет циклов, т. е. путей, связывающих между собою не
«родственные» элементы.
ProPowerPoint.Ru
Списки
Виды по количеству связей:
Односвязные
В структуру входит только
указатель на следующий
элемент. Если указатель пуст
(имеет
специальное
значение
nil),
то
это
последний элемент.
Двусвязные
В
структуру
входят
указатели на следующий и
на предыдущий элементы,
т. е. можно двигаться не
только «вперед», но и
«назад».
Можем рассматривать не
только "голову", но и "хвост".
Примечание: мы будем рассматривать двусвязные списки.
ProPowerPoint.Ru
Основные операции
• Указатель на «голову» списка хранится в переменной head.
• Пустое значение указателя обозначим в коде как nil.
1. Добавление элемента в «голову» списка:
newListItem = new ListItem //добавляем новый элемент
newListItem.next = head //нынешнее первое «спускаем»
newListItem.prev = nil //пустое значение предыдущего, т.к. его нет.
if (head <> nil) // если список существовал
head.prev = newListItem //вносим элемент первым
head = newListItem //заносим значение как «голову»
Сложность алгоритма: О(1)
Алгоритм не зависит от размеров списка.
ProPowerPoint.Ru
2. Поиск элемента в списке:
(т. е. элемента со значением данных target)
currItem = head //начинаем с «головы»
while ((currItem <> nil)and(currItem.data <> target))
//до тех пор, пока у нас есть список и элемент не найден
currItem = currItem.next //проходим дальше, переобозначая
Сложность алгоритма: О(n)
В худшем случае необходимо проверить весь список.
3. Удаление элемента из списка:
If (delItem.next <> nil) //если след. элемент есть (не пуст)
delItem.next.prev = delItem.prev //сдвигаем назад
if (delItem.prev <> nil) //если пред.элемент не пуст
delItem.prev.next = delItem.next // «перешагиваем» на след.
delete delItem //удаляем нужный элемент
При удалении элемента из списка важно сохранить его
связность. Поэтому сначала мы исключаем элемент из
цепочки, а потом освобождаем занятую им память.
Сложность алгоритма: Если элемент не нужно искать (например,
мы удаляем элемент из «головы» списка), то количество действий
останется O(1), если нужно, то O(n).
ProPowerPoint.Ru
Чем полезен список?
• Задание:
Подумайте над вопросом, чем удобней в применении список
по сравнению с массивом и когда он хуже.
• Резюмируя результаты:
+
1. если заранее неизвестно
количество элементов;
2. не нужно заботиться о
выходе за границы;
3. позволяет быстро
производить вставку,
удаление элементов.
ProPowerPoint.Ru
1. неудобен, когда нужен
быстрый доступ к
произвольному элементу
(необходимо проходить
каждый раз весь список или
хранить указатели в
отдельном массиве).
Дерево
• имеют минимум два возможных выхода из каждого
элемента;
• не имеют циклов.
Вершина - любой (каждый) в дереве; содержит указатели на
потомков и некоторые данные программиста (аналогично списку).
Ключ - часть данных, от которой зависит обработка дерева.
Мы будем рассматривать двоичные деревья (имеющие ровно два
выхода), т.е. элементом такого дерева является структура,
содержащая:
•указатель левой ветви,
•указатель правой ветви,
•некоторые полезные данные (например, некоторое число).
ProPowerPoint.Ru
Двоичные деревья
Элемент N
(текущий)
n
Элемент Q
q
q<n
ProPowerPoint.Ru
Элемент P
p
p≥n
Операции над деревьями
• Дерево хранится как указатель на его первый элемент,
который называется корневым.
• Будем считать, что указатель на корень дерева хранится в
переменной root.
1. Поиск элемента в дереве:
curItem = root //начинаем с корня
while ((curItem <> nil)and(curItem.data <> a))
//пока дерево не кончилось и элемент не нашёлся
if (curItem.data > a) //рассматриваем элемент
curItem = curItem.left //присваиваем меньшее значение («левое»)
else
curItem = curItem.right //присваиваем большее или равное значение
//(«правое»)
Если элемента в дереве нет, то последним текущим элементом
станет nil.
Сложность алгоритма: зависит от кол-ва элементов дерева и
порядка, в котором их добавляли.
ProPowerPoint.Ru
2. Вставка элемента в дерево:
Сложность алгоритма: если дерево сбалансировано – О(log n), если в
дерево элементы добавлялись неудачно (например, по возрастанию),
оно становится списком, а сложность возрастает до О(n).
Дерево называется сбалансированным, если в нём мало или совсем
нет узлов с одним потомком.
ProPowerPoint.Ru
Типовые структуры данных
ProPowerPoint.Ru
Стек (stack)
Линейная структура данных, в которой есть две
операции: помещения и извлечения. При извлечении
всегда выдается
последний помещенный в структуру элемент. Такой
принцип называется LIFO ( Last In First Out, т.е.
«последний зашёл – первый вышел»).
Пример-аналогия: стопка тарелок (можно брать только
последнюю) или люди в набитом автобусе.
Очередь
Линейная структура с двумя операциями, но
извлекается не последний, а первый помещенный
элемент, т.е. используется принцип FIFO (First In First
Out).
Пример-аналогия: очередь в магазине (первый встал первый купил и вышел).
Двоичное
дерево
поиска
В этом дереве каждый элемент имеет не более двух
потомков, причем левый меньше текущего ключа, а
правый больше.
Могут быть реализованы и с помощью динамических, и с
помощью статических структур.
Практическая часть
1. Вас просят написать программу, которая получает данные о книгах. О каждой
книге будет известно название, автор, цена, количество и расположение на
складе. Общее количество книг заранее неизвестно. Опишите структуру
данных, которую целесообразно использовать для хранения.
program task4_18_1;
Type
book = record // Структура для хранения данных о конкретной книге на складе
title : string;
author: string;
count : word;
price : longword;
place : word;
end;
pNode = ^ListNode; // Общая структура для организации учета склада
ListNode = record
next : pNode;
bookData : book;
end;
// Добавление элемента в список
function itemListNew (title : string;
author: string; count : word;
price : longword;
place : word;
next : PNode):pNode;
begin
new (Result);
Result^.bookData.title := title;
Result^.bookData.author := author;
Result^.bookData.count := count;
Result^.bookData.price := price;
Result^.bookData.place := place;
Result^.next := next;
end;
// Ввод данных о книге с клавиатуры
function itemListKeyboard (next : pNode) : pNode;
var
title, author: string;
ProPowerPoint.Ru
count : word;
price : longword;
place : word;
begin
write ('Введите название==>'); readln(title);
write ('Введите автора==>'); readln(author);
write ('Введите количество==>'); readln(count);
write ('Введите цену==>'); readln(price);
write ('Введите место==>'); readln(place);
Result := itemListNew (title,author,count,price,place, next);
end;
var
head : pNode;
answ : char;
begin
// Создание списка
repeat
write('Желаете ввести новую книгу?(д/н)');
readln(answ);
if answ = 'д' then
head := itemListKeyboard(head);
until answ <> 'д';
end.
//Вывод списка в этой задаче не требовался.
Для рассмотрения скопируйте код в
компилятор!
2. Подготовьте программу, которая вводит и выводит данные о книгах. Вводиться
будут данные из предыдущей задачи, а выводиться название и общая
стоимость книг этого наименования.
program task4_18_2;
writeln(item^.bookData.title,',',item^.book
Type
begin
Data.price*item^.bookData.count);
book = record // Структура для хранения new (Result);
result := item^.next;
данных о конкретной книге на складе Result^.bookData.title := title;
end;
title : string;
Result^.bookData.author := author;
author: string;
Result^.bookData.count := count;
var
count : word;
Result^.bookData.price := price;
head : pNode;
price : longword;
Result^.bookData.place := place;
answ : char;
place : word;
Result^.next := next;
begin
end;
end;
// Создание списка
pNode = ^ListNode; // Общая структура
repeat
для организации учета склада
// Ввод данных о книге с клавиатуры
write('Желаете ввести новую
ListNode = record
function itemListKeyboard (next : pNode) книгу?(д/н)');
next : pNode;
: pNode;
readln(answ);
bookData : book;
var
if answ = 'д' then
end;
title, author: string;
head := itemListKeyboard(head);
// Функция-итератор, подробно
count : word;
until answ <> 'д';
рассмотренная в задачнике
price : longword;
iterate = function( item : pNode): pNode; place : word;
iteratorList(head,printListItem); // Вывод
procedure iteratorList(start : pNode;
begin
всех значений списка – решение задачи
iterateFunction : iterate);
write ('Введите название==>');
2
var
readln(title);
end.
current : pNode;
write ('Введите автора==>');
begin
readln(author);
current := start;
write ('Введите количество==>');
repeat
readln(count);
current:=iterateFunction(current);
write ('Введите цену==>'); readln(price);
until current = nil;
write ('Введите место==>'); readln(place);
end;
Result := itemListNew
// Добавление элемента в список
(title,author,count,price,place, next);
function itemListNew (title : string;
end;
author: string; count : word;
price : longword;
function printListItem (item : pNode) :
place : word;
pNode;
next : PNode):pNode;
begin
ProPowerPoint.Ru
3. Подготовьте программу, которая выведет только книги заданного автора.
ProPowerPoint.Ru
program task4_18_3;
new (Result);
Result := itemListNew
Type
Result^.bookData.title := title;
(title,author,count,price,place, next);
book = record // Структура для хранения Result^.bookData.author := author;
end;
данных о конкретной книге на складе Result^.bookData.count := count;
title : string;
Result^.bookData.price := price;
function printListItem (item : pNode) :
author: string;
Result^.bookData.place := place;
pNode;
count : word;
Result^.next := next;
begin
price : longword;
end;
writeln(item^.bookData.title,',',item^.book
place : word;
Data.price*item^.bookData.count);
end;
function printListItemAuthor (item :
result := item^.next;
pNode = ^ListNode; // Общая структура pNode) :
end;
для организации учета склада
pNode;
ListNode = record
begin
var
next : pNode;
if item^.bookData.author='Калинин
head : pNode;
bookData : book;
И.А.,Самылкина Н.Н.' then
answ : char;
end;
writeln(item^.bookData.author,',',item^.bobegin
// Функция-итератор, подробно
okData.title,',',item^.bookData.price);
// Создание списка
рассмотренная в задачнике
result := item^.next;
head := itemListNew ('Информатика iterate = function( item : pNode): pNode; end;
10','Калинин И.А.,Самылкина
procedure iteratorList(start : pNode;
Н.Н.',10,210,1,nil);
iterateFunction : iterate);
// Ввод данных о книге с клавиатуры
head := itemListNew ('Информатика var
function itemListKeyboard (next : pNode) 11','Калинин И.А.,Самылкина
current : pNode;
: pNode;
Н.Н.',10,180,1,head);
begin
var
repeat
current := start;
title, author: string;
write('Желаете ввести новую
repeat
count : word;
книгу?(д/н)');
current:=iterateFunction(current);
price : longword;
readln(answ);
until current = nil;
place : word;
if answ = 'д' then
end;
begin
head := itemListKeyboard(head);
// Добавление элемента в список
write ('Введите название==>');
until answ <> 'д';
function itemListNew (title : string;
readln(title);
writeLn('Книги искомого автора(ов):');
author: string; count : word;
write ('Введите автора==>');
iteratorList(head, printListItemAuthor);
price : longword;
readln(author);
end.
place : word;
write ('Введите количество==>');
next : PNode):pNode;
readln(count);
write ('Введите цену==>'); readln(price);
begin
write ('Введите место==>'); readln(place);
4*. Опишите структуру, которая позволит вводить данные о нескольких авторах и
их книгах (неизвестно заранее, сколько их будет), а также по желанию
пользователя дополнять описание книг атрибутами (например, ключевыми
словами).
//Универсальная структура хранения данных. До 65535 типов атрибутов.
pAttribute = ^attribute;
attribute = record;
nextAttribute : pAttribute;
attributeType : word; //Тип атрибута: 1 - автор, 2 - название, 3 - ключевое
//слово и т.д.
attributeNumber : longword; //Значение атрибута - число
attributeString : longword; //Значение атрибута - строка
end;
pBook = ^BookUniversal;
bookUniversal = record //Книга, обладающая любым кол-вом атрибутов
next : pBook;
attributeList :pAttribute;
end;
Примечания: для удобства необходимо оговорить нумерацию
атрибутов (например, составить отдельную таблицу соответствия).
Некоторые атрибуты могут встречаться несколько раз.
*Требуется только описать структуру, а не программу.
ProPowerPoint.Ru
5. Опишите структуру данных, которая может быть использована для
определения растения по наличию или отсутствию признаков (т. е. признак
либо есть, либо нет).
Ответом будет построение двоичного дерева, описанного в учебнике и
рассмотренного здесь ранее.
pBinaryNode = ^BinaryTreeNode; //необходимая структура
BinaryTreeNode = record
left,right : pNode; //Правая и левая ветви – записи.
queryText : string; //Содержат текстовое описание признаков.
end;
*Требуется только описать структуру, а не программу.
ProPowerPoint.Ru
6. Напишите программу, определяющую растение заданного семейства по
стандартной определительной карте (например, крестоцветное).
program task4_18_6;
type
pNode = ^TreeNode;
TreeNode = record
left, right: pNode;
leftText, rightText: string;
end;
function itemListNew(leftText: string):
pNode;
begin
new(Result);
Result^.leftText := leftText;
Result^.left := nil;
Result^.right := nil;
end;
procedure infoNode(current: pNode);
var
leftText, rightText: string;
begin
leftText := 'Споранхии есть.';
current^.leftText := leftText;
rightText := 'Споранхий нет.';
current^.rightText := rightText;
leftText := 'Зрелый лист.';
current^.left := itemListNew(leftText);
rightText := 'Молодой лист.';
current^.right := itemListNew(rightText);
end;
ProPowerPoint.Ru
var
answ: char;
head, current: pNode;
begin
head := itemListNew('Что-то живое');
current := head;
infoNode(current);
begin
writeln('Вариант 1: ',
current^.leftText);
writeln('Вариант 2: ',
current^.rightText);
writeln('Выберите вариант 1 или 2
');
readln(answ);
if answ = '1' then
current := current^.left
else
current := current^.right;
writeln('У нас есть только один
вариант: ', current^.leftText);
end;
end.
7*. Напишите программу, которая позволит расширить карту.
program task4_18_7;
type
pNode = ^TreeNode;
TreeNode = record
left, right: pNode;
leftText, rightText: string;
end;
function itemListNew(leftText: string):
pNode;
begin
new(Result);
Result^.leftText := leftText;
Result^.left := nil;
Result^.right := nil;
end;
ProPowerPoint.Ru
procedure newNode(current: pNode);
var
leftText, rightText: string;
answ: char;
begin
writeln('Ввведите признак первого
варианта ');
readln(leftText);
current^.leftText := leftText;
writeln('Ввведите признак второго
варианта ');
readln(rightText);
current^.rightText := rightText;
writeln('Ввведите вывод по первому
варианту ');
readln(leftText);
current^.left := itemListNew(leftText);
writeln('Ввведите вывод по второму
writeln('У нас есть только один
варианту ');
вариант: ', current^.leftText);
readln(rightText);
writeln('Желаете добавить
current^.right := itemListNew(rightText); ветвление? (д/н)');
readln(answ);
end;
if answ = 'д' then
newNode(current);
var
end;
answ: char;
end;
head, current: pNode;
writeln('Желаете повторить
определение? (д/н)');
begin
readln(answ);
head := itemListNew('Что-то живое');
until answ = 'н';
current := head;
end.
repeat
while current <> nil do
begin
if current^.leftText <> '' then
writeln('Вариант 1: ',
current^.leftText);
if current^.leftText <> '' then
writeln('Вариант 2: ',
current^.rightText);
if (current^.left <> nil) and
(current^.right <> nil) then
begin
writeln('Выберите вариант 1 или 2
');
readln(answ);
if answ = '1' then
current := current^.left
else
current := current^.right;
end
else
begin
Download