Алгоритмизация и программирование Структуры данных 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