🗊Презентация Нелинейные структуры данных. (Тема 4)

Нажмите для полного просмотра!
Нелинейные структуры данных. (Тема 4), слайд №1Нелинейные структуры данных. (Тема 4), слайд №2Нелинейные структуры данных. (Тема 4), слайд №3Нелинейные структуры данных. (Тема 4), слайд №4Нелинейные структуры данных. (Тема 4), слайд №5Нелинейные структуры данных. (Тема 4), слайд №6Нелинейные структуры данных. (Тема 4), слайд №7Нелинейные структуры данных. (Тема 4), слайд №8Нелинейные структуры данных. (Тема 4), слайд №9Нелинейные структуры данных. (Тема 4), слайд №10Нелинейные структуры данных. (Тема 4), слайд №11Нелинейные структуры данных. (Тема 4), слайд №12Нелинейные структуры данных. (Тема 4), слайд №13Нелинейные структуры данных. (Тема 4), слайд №14Нелинейные структуры данных. (Тема 4), слайд №15Нелинейные структуры данных. (Тема 4), слайд №16Нелинейные структуры данных. (Тема 4), слайд №17Нелинейные структуры данных. (Тема 4), слайд №18Нелинейные структуры данных. (Тема 4), слайд №19Нелинейные структуры данных. (Тема 4), слайд №20Нелинейные структуры данных. (Тема 4), слайд №21Нелинейные структуры данных. (Тема 4), слайд №22Нелинейные структуры данных. (Тема 4), слайд №23Нелинейные структуры данных. (Тема 4), слайд №24Нелинейные структуры данных. (Тема 4), слайд №25Нелинейные структуры данных. (Тема 4), слайд №26Нелинейные структуры данных. (Тема 4), слайд №27Нелинейные структуры данных. (Тема 4), слайд №28Нелинейные структуры данных. (Тема 4), слайд №29Нелинейные структуры данных. (Тема 4), слайд №30Нелинейные структуры данных. (Тема 4), слайд №31Нелинейные структуры данных. (Тема 4), слайд №32Нелинейные структуры данных. (Тема 4), слайд №33Нелинейные структуры данных. (Тема 4), слайд №34Нелинейные структуры данных. (Тема 4), слайд №35Нелинейные структуры данных. (Тема 4), слайд №36Нелинейные структуры данных. (Тема 4), слайд №37Нелинейные структуры данных. (Тема 4), слайд №38Нелинейные структуры данных. (Тема 4), слайд №39Нелинейные структуры данных. (Тема 4), слайд №40Нелинейные структуры данных. (Тема 4), слайд №41Нелинейные структуры данных. (Тема 4), слайд №42Нелинейные структуры данных. (Тема 4), слайд №43Нелинейные структуры данных. (Тема 4), слайд №44Нелинейные структуры данных. (Тема 4), слайд №45Нелинейные структуры данных. (Тема 4), слайд №46Нелинейные структуры данных. (Тема 4), слайд №47Нелинейные структуры данных. (Тема 4), слайд №48Нелинейные структуры данных. (Тема 4), слайд №49Нелинейные структуры данных. (Тема 4), слайд №50Нелинейные структуры данных. (Тема 4), слайд №51Нелинейные структуры данных. (Тема 4), слайд №52Нелинейные структуры данных. (Тема 4), слайд №53Нелинейные структуры данных. (Тема 4), слайд №54Нелинейные структуры данных. (Тема 4), слайд №55Нелинейные структуры данных. (Тема 4), слайд №56Нелинейные структуры данных. (Тема 4), слайд №57Нелинейные структуры данных. (Тема 4), слайд №58Нелинейные структуры данных. (Тема 4), слайд №59Нелинейные структуры данных. (Тема 4), слайд №60Нелинейные структуры данных. (Тема 4), слайд №61Нелинейные структуры данных. (Тема 4), слайд №62Нелинейные структуры данных. (Тема 4), слайд №63Нелинейные структуры данных. (Тема 4), слайд №64Нелинейные структуры данных. (Тема 4), слайд №65Нелинейные структуры данных. (Тема 4), слайд №66Нелинейные структуры данных. (Тема 4), слайд №67Нелинейные структуры данных. (Тема 4), слайд №68Нелинейные структуры данных. (Тема 4), слайд №69Нелинейные структуры данных. (Тема 4), слайд №70Нелинейные структуры данных. (Тема 4), слайд №71Нелинейные структуры данных. (Тема 4), слайд №72Нелинейные структуры данных. (Тема 4), слайд №73Нелинейные структуры данных. (Тема 4), слайд №74Нелинейные структуры данных. (Тема 4), слайд №75Нелинейные структуры данных. (Тема 4), слайд №76Нелинейные структуры данных. (Тема 4), слайд №77Нелинейные структуры данных. (Тема 4), слайд №78Нелинейные структуры данных. (Тема 4), слайд №79Нелинейные структуры данных. (Тема 4), слайд №80Нелинейные структуры данных. (Тема 4), слайд №81Нелинейные структуры данных. (Тема 4), слайд №82Нелинейные структуры данных. (Тема 4), слайд №83Нелинейные структуры данных. (Тема 4), слайд №84Нелинейные структуры данных. (Тема 4), слайд №85Нелинейные структуры данных. (Тема 4), слайд №86Нелинейные структуры данных. (Тема 4), слайд №87Нелинейные структуры данных. (Тема 4), слайд №88Нелинейные структуры данных. (Тема 4), слайд №89Нелинейные структуры данных. (Тема 4), слайд №90Нелинейные структуры данных. (Тема 4), слайд №91Нелинейные структуры данных. (Тема 4), слайд №92Нелинейные структуры данных. (Тема 4), слайд №93Нелинейные структуры данных. (Тема 4), слайд №94Нелинейные структуры данных. (Тема 4), слайд №95Нелинейные структуры данных. (Тема 4), слайд №96

Содержание

Вы можете ознакомиться и скачать презентацию на тему Нелинейные структуры данных. (Тема 4). Доклад-сообщение содержит 96 слайдов. Презентации для любого класса можно скачать бесплатно. Если материал и наш сайт презентаций Mypresentation Вам понравились – поделитесь им с друзьями с помощью социальных кнопок и добавьте в закладки в своем браузере.

Слайды и текст этой презентации


Слайд 1





Тема 4
НЕЛИНЕЙНЫЕ СТРУКТУРЫ ДАННЫХ
Описание слайда:
Тема 4 НЕЛИНЕЙНЫЕ СТРУКТУРЫ ДАННЫХ

Слайд 2






Нелинейные структуры данных позволяют выражать более сложные отношения между элементами, нежели линейные отношения соседства, как это было в линейных списках. 
К нелинейным структурам данных относят 
графы, 
деревья 
и леса. 
Эти структуры находят широкое применение при решении практических задач. 
В данной теме достаточно полно будут рассмотрены способы построения и представления деревьев и основные операции над ними. 
Вопросы представления графов и алгоритмы на графах рассмотрим позже.
Описание слайда:
Нелинейные структуры данных позволяют выражать более сложные отношения между элементами, нежели линейные отношения соседства, как это было в линейных списках. К нелинейным структурам данных относят графы, деревья и леса. Эти структуры находят широкое применение при решении практических задач. В данной теме достаточно полно будут рассмотрены способы построения и представления деревьев и основные операции над ними. Вопросы представления графов и алгоритмы на графах рассмотрим позже.

Слайд 3






Деревья
Описание слайда:
Деревья

Слайд 4






Деревья представляют собой иерархическую структуру некой совокупности элементов. 
Примерами деревьев могут служить генеалогические и организационные диаграммы. 
Деревья используются при анализе электрических цепей, при представлении структур математических формул. 
Они также естественным путем возникают во многих областях компьютерных наук. 
Например, деревья используются для организации информации в системах управления базами данных и для представления синтаксических структур в компиляторах программ.
Описание слайда:
Деревья представляют собой иерархическую структуру некой совокупности элементов. Примерами деревьев могут служить генеалогические и организационные диаграммы. Деревья используются при анализе электрических цепей, при представлении структур математических формул. Они также естественным путем возникают во многих областях компьютерных наук. Например, деревья используются для организации информации в системах управления базами данных и для представления синтаксических структур в компиляторах программ.

Слайд 5





Основная терминология 
Дерево - это совокупность элементов, называемых узлами (один из которых определен как корень), и отношений ("родительских"), образующих иерархическую структуру узлов. 
Узлы, так же, как и элементы списков, могут быть элементами любого типа. Мы часто будем изображать узлы буквами, строками или числами.
Описание слайда:
Основная терминология Дерево - это совокупность элементов, называемых узлами (один из которых определен как корень), и отношений ("родительских"), образующих иерархическую структуру узлов. Узлы, так же, как и элементы списков, могут быть элементами любого типа. Мы часто будем изображать узлы буквами, строками или числами.

Слайд 6





Основная терминология 
Формально дерево можно рекуррентно определить следующим образом: 
1. Один узел является деревом. Этот же узел также является корнем этого дерева. 
2. Пусть n - это узел, а Т1, Т2, …, Тk - деревья с корнями n1, n2, …, nk соответственно. Можно построить новое дерево, сделав n родителем узлов n1, n2, …, nk. В этом дереве n будет корнем, а Т1, Т2, …, Тk - поддеревьями этого корня. Узлы n1, n2, …, nk называются сыновьями узла n. 
Часто в это определение включают понятие нулевого дерева, т.е. "дерева" без узлов, такое дерево мы будем обозначать символом .
Описание слайда:
Основная терминология Формально дерево можно рекуррентно определить следующим образом: 1. Один узел является деревом. Этот же узел также является корнем этого дерева. 2. Пусть n - это узел, а Т1, Т2, …, Тk - деревья с корнями n1, n2, …, nk соответственно. Можно построить новое дерево, сделав n родителем узлов n1, n2, …, nk. В этом дереве n будет корнем, а Т1, Т2, …, Тk - поддеревьями этого корня. Узлы n1, n2, …, nk называются сыновьями узла n. Часто в это определение включают понятие нулевого дерева, т.е. "дерева" без узлов, такое дерево мы будем обозначать символом .

Слайд 7





Пример 1 
Рассмотрим оглавление книги, схематически представленное на рис. 1, а. Это оглавление является деревом, которое в другой форме показано на рис. 1, б. 
Отношение родитель-сын отображается в виде линии. Деревья обычно рисуются сверху вниз, как на рис. 1, б, так, что родители располагаются выше "детей". 
Рис. 1
Пример 1 показывает типичные данные, для которых наилучшим представлением будут деревья. В этом примере родительские отношения устанавливают подчиненность глав и разделов: родительский узел связан с узлами сыновей (и указывает на них), как узел Книга подчиняет себе узлы Гл.1, Гл.2 и Гл.З.
Описание слайда:
Пример 1 Рассмотрим оглавление книги, схематически представленное на рис. 1, а. Это оглавление является деревом, которое в другой форме показано на рис. 1, б. Отношение родитель-сын отображается в виде линии. Деревья обычно рисуются сверху вниз, как на рис. 1, б, так, что родители располагаются выше "детей". Рис. 1 Пример 1 показывает типичные данные, для которых наилучшим представлением будут деревья. В этом примере родительские отношения устанавливают подчиненность глав и разделов: родительский узел связан с узлами сыновей (и указывает на них), как узел Книга подчиняет себе узлы Гл.1, Гл.2 и Гл.З.

Слайд 8





Основная терминология 
Путем из узла n1 в узел nk называется последовательность узлов n1, n2, …, nk, где для всех i, 1 ≤ i ≤ k, узел ni является родителем узла ni+1. 
Длиной пути называется число, на единицу меньшее числа узлов, составляющих этот путь. Таким образом, путем нулевой длины будет путь из любого узла к самому себе. На рис. 1 путем длины 2 будет, например, путь от узла Гл.2 к узлу Р.2.1.2.
Описание слайда:
Основная терминология Путем из узла n1 в узел nk называется последовательность узлов n1, n2, …, nk, где для всех i, 1 ≤ i ≤ k, узел ni является родителем узла ni+1. Длиной пути называется число, на единицу меньшее числа узлов, составляющих этот путь. Таким образом, путем нулевой длины будет путь из любого узла к самому себе. На рис. 1 путем длины 2 будет, например, путь от узла Гл.2 к узлу Р.2.1.2.

Слайд 9





Основная терминология 
Если существует путь из узла а в b, то в этом случае узел а называется предком узла b, а узел b - потомком узла а. 
Например, на рис. 1 предками узла Р.2.1 будут следующие узлы: сам узел Р.2.1 и узлы Гл.2 и Книга, тогда как потомками этого узла являются опять сам узел Р.2.1 и узлы Р.2.1.1 и Р.2.1.2. 
Отметим, что любой узел одновременно является и предком, и потомком самого себя. 
Предок или потомок узла, не являющийся таковым самого себя, называется истинным предком или истинным потомком соответственно. 
В дереве только корень не имеет истинного предка. 
Узел, не имеющий истинных потомков, называется листом. 
Теперь поддерево какого-либо дерева можно определить как узел (корень поддерева) вместе со всеми его потомками.
Описание слайда:
Основная терминология Если существует путь из узла а в b, то в этом случае узел а называется предком узла b, а узел b - потомком узла а. Например, на рис. 1 предками узла Р.2.1 будут следующие узлы: сам узел Р.2.1 и узлы Гл.2 и Книга, тогда как потомками этого узла являются опять сам узел Р.2.1 и узлы Р.2.1.1 и Р.2.1.2. Отметим, что любой узел одновременно является и предком, и потомком самого себя. Предок или потомок узла, не являющийся таковым самого себя, называется истинным предком или истинным потомком соответственно. В дереве только корень не имеет истинного предка. Узел, не имеющий истинных потомков, называется листом. Теперь поддерево какого-либо дерева можно определить как узел (корень поддерева) вместе со всеми его потомками.

Слайд 10





Основная терминология 
Высотой узла дерева называется длина самого длинного пути из этого узла до какого-либо листа. 
На рис.1 высота узла Гл.1 равна 1, узла Гл.2 - 2, а узла Гл.З - 0. 
Высота дерева совпадает с высотой корня. 
Глубина узла определяется как длина пути (он единственный) от корня до этого узла.
Описание слайда:
Основная терминология Высотой узла дерева называется длина самого длинного пути из этого узла до какого-либо листа. На рис.1 высота узла Гл.1 равна 1, узла Гл.2 - 2, а узла Гл.З - 0. Высота дерева совпадает с высотой корня. Глубина узла определяется как длина пути (он единственный) от корня до этого узла.

Слайд 11





Порядок узлов 
Сыновья узла обычно упорядочиваются слева направо. Поэтому два дерева на рисунке  различны, так как порядок сыновей узла а различен. 
Если порядок сыновей игнорируется, то такое дерево называется неупорядоченным, в противном случае дерево называется упорядоченным.
Описание слайда:
Порядок узлов Сыновья узла обычно упорядочиваются слева направо. Поэтому два дерева на рисунке различны, так как порядок сыновей узла а различен. Если порядок сыновей игнорируется, то такое дерево называется неупорядоченным, в противном случае дерево называется упорядоченным.

Слайд 12





Порядок узлов 
Упорядочивание слева направо сыновей ("родных детей" одного узла) можно использовать для сопоставления узлов, которые не связаны отношениями предки-потомки. 
Соответствующее правило звучит следующим образом: 
если узлы а и b являются сыновьями одного родителя и узел а лежит слева от узла b, то все потомки узла а будут находиться слева от любых потомков узла b.
Описание слайда:
Порядок узлов Упорядочивание слева направо сыновей ("родных детей" одного узла) можно использовать для сопоставления узлов, которые не связаны отношениями предки-потомки. Соответствующее правило звучит следующим образом: если узлы а и b являются сыновьями одного родителя и узел а лежит слева от узла b, то все потомки узла а будут находиться слева от любых потомков узла b.

Слайд 13





Пример 2. 
Рассмотрим дерево на рисунке. 
Узел 8 расположен справа от узла 2, слева от узлов 9, 6, 10, 4 и 7 и не имеет отношений справа-слева относительно предков 1, 3 и 5.
Описание слайда:
Пример 2. Рассмотрим дерево на рисунке. Узел 8 расположен справа от узла 2, слева от узлов 9, 6, 10, 4 и 7 и не имеет отношений справа-слева относительно предков 1, 3 и 5.

Слайд 14





Прямой, обратный и симметричный обходы дерева 
Существует несколько способов обхода (прохождения) всех узлов дерева. Обход узлов дерева равнозначен упорядочиванию по какому-либо правилу этих узлов. Поэтому в данном разделе мы будем использовать слова "обход узлов" и "упорядочивание узлов" как синонимы. 
Три наиболее часто используемых способа обхода дерева называются 
обход в прямом порядке, 
обход в обратном порядке 
и обход во внутреннем порядке (последний вид обхода также часто называют симметричным обходом). 
Все три способа обхода рекурсивно можно определить следующим образом.
Описание слайда:
Прямой, обратный и симметричный обходы дерева Существует несколько способов обхода (прохождения) всех узлов дерева. Обход узлов дерева равнозначен упорядочиванию по какому-либо правилу этих узлов. Поэтому в данном разделе мы будем использовать слова "обход узлов" и "упорядочивание узлов" как синонимы. Три наиболее часто используемых способа обхода дерева называются обход в прямом порядке, обход в обратном порядке и обход во внутреннем порядке (последний вид обхода также часто называют симметричным обходом). Все три способа обхода рекурсивно можно определить следующим образом.

Слайд 15





Прямой, обратный и симметричный обходы дерева 
Если дерево Т является нулевым деревом, то в список обхода заносится пустая запись. 
Если дерево Т состоит из одного узла, то в список обхода записывается этот узел. 
Далее, пусть Т - дерево с корнем n и поддеревьями T1, T2, ..., Тk, как показано на рисунке.
Описание слайда:
Прямой, обратный и симметричный обходы дерева Если дерево Т является нулевым деревом, то в список обхода заносится пустая запись. Если дерево Т состоит из одного узла, то в список обхода записывается этот узел. Далее, пусть Т - дерево с корнем n и поддеревьями T1, T2, ..., Тk, как показано на рисунке.

Слайд 16





Прямой, обратный и симметричный обходы дерева 
Тогда для различных способов обхода имеем следующее. 
1. При прохождении в прямом порядке (т.е. при прямом упорядочивании) узлов дерева Т сначала посещается корень n, затем узлы поддерева Т1, далее все узлы поддерева Т2 и т.д. Последними посещаются узлы поддерева Тk. 
2. При симметричном обходе узлов дерева Т сначала посещаются в симметричном порядке все узлы поддерева Т1, далее корень n, затем последовательно в симметричном порядке все узлы поддеревьев Т2, …, Тk. 
3. Во время обхода в обратном порядке сначала посещаются в обратном порядке все узлы поддерева Т1, затем последовательно посещаются все узлы поддеревьев Т2, …, Тk, также в обратном порядке, последним посещается корень n.
Описание слайда:
Прямой, обратный и симметричный обходы дерева Тогда для различных способов обхода имеем следующее. 1. При прохождении в прямом порядке (т.е. при прямом упорядочивании) узлов дерева Т сначала посещается корень n, затем узлы поддерева Т1, далее все узлы поддерева Т2 и т.д. Последними посещаются узлы поддерева Тk. 2. При симметричном обходе узлов дерева Т сначала посещаются в симметричном порядке все узлы поддерева Т1, далее корень n, затем последовательно в симметричном порядке все узлы поддеревьев Т2, …, Тk. 3. Во время обхода в обратном порядке сначала посещаются в обратном порядке все узлы поддерева Т1, затем последовательно посещаются все узлы поддеревьев Т2, …, Тk, также в обратном порядке, последним посещается корень n.

Слайд 17





Листинг 4.1. Рекурсивные процедуры обхода деревьев 
procedure  PREORDER ( n: узел ); 
begin 
(1) 	занести в список обхода узел n; 
(2) 	для каждого сына с узла n в порядке слева направо 		do 
			PREORDER(с) 
end; 		{ PREORDER } 
Здесь показан набросок процедуры PREORDER (Прямое упорядочивание), составляющей список узлов дерева при обходе его в прямом порядке. 
Чтобы из этой процедуры сделать процедуру, выполняющую обход дерева в обратном порядке, надо просто поменять местами строки (1) и (2).
Описание слайда:
Листинг 4.1. Рекурсивные процедуры обхода деревьев procedure PREORDER ( n: узел ); begin (1) занести в список обхода узел n; (2) для каждого сына с узла n в порядке слева направо do PREORDER(с) end; { PREORDER } Здесь показан набросок процедуры PREORDER (Прямое упорядочивание), составляющей список узлов дерева при обходе его в прямом порядке. Чтобы из этой процедуры сделать процедуру, выполняющую обход дерева в обратном порядке, надо просто поменять местами строки (1) и (2).

Слайд 18





Листинг 4.1. Рекурсивные процедуры обхода деревьев 
procedure   INORDER ( n: узел ); 
begin 
	if   n - лист   then  
		занести в список обхода узел n; 
	else    begin 
		INORDER(самый левый сын узла n); 
		занести в список обхода узел n; 
		для каждого сына с узла n, исключая самый 				левый, в порядке слева направо   do 
				INORDER(с) 
	end 
end; 		{ INORDER } 

Здесь представлен набросок процедуры INORDER (Внутреннее упорядочивание).
Описание слайда:
Листинг 4.1. Рекурсивные процедуры обхода деревьев procedure INORDER ( n: узел ); begin if n - лист then занести в список обхода узел n; else begin INORDER(самый левый сын узла n); занести в список обхода узел n; для каждого сына с узла n, исключая самый левый, в порядке слева направо do INORDER(с) end end; { INORDER } Здесь представлен набросок процедуры INORDER (Внутреннее упорядочивание).

Слайд 19





Пример 3. Прямой обход дерева 
Сначала запишем (посетим) узел 1, затем вызовем процедуру PREORDER для обхода первого поддерева с корнем 2. Это поддерево состоит из одного узла, которое мы и записываем. 
Далее обходим второе поддерево, выходящее из корня 1, это поддерево имеет корень 3. Записываем узел 3 и вызываем процедуру PREORDER для обхода первого поддерева, выходящего из узла 3. В результате получим список узлов 5, 8 и 9 (именно в таком порядке). 
Продолжая этот процесс, в конце мы получим полный список узлов, посещаемых при прохождении в прямом порядке исходного дерева: 
1, 2, 3, 5, 8, 9, 6, 10, 4 и 7.
Описание слайда:
Пример 3. Прямой обход дерева Сначала запишем (посетим) узел 1, затем вызовем процедуру PREORDER для обхода первого поддерева с корнем 2. Это поддерево состоит из одного узла, которое мы и записываем. Далее обходим второе поддерево, выходящее из корня 1, это поддерево имеет корень 3. Записываем узел 3 и вызываем процедуру PREORDER для обхода первого поддерева, выходящего из узла 3. В результате получим список узлов 5, 8 и 9 (именно в таком порядке). Продолжая этот процесс, в конце мы получим полный список узлов, посещаемых при прохождении в прямом порядке исходного дерева: 1, 2, 3, 5, 8, 9, 6, 10, 4 и 7.

Слайд 20





Пример 3. Обратный и симметричный обходы дерева 
Подобным образом, предварительно преобразовав процедуру PREORDER в процедуру, выполняющую обход в обратном порядке (как указано выше), можно получить обратное упорядочивание узлов дерева в следующем виде: 
2, 8, 9, 5, 10, 6, 3, 7, 4 и 1. 
Применяя процедуру INORDER, получим список симметрично упорядоченных узлов этого же дерева: 
2, 1, 8, 5, 9, 3, 10, 6, 7 и 4.
Описание слайда:
Пример 3. Обратный и симметричный обходы дерева Подобным образом, предварительно преобразовав процедуру PREORDER в процедуру, выполняющую обход в обратном порядке (как указано выше), можно получить обратное упорядочивание узлов дерева в следующем виде: 2, 8, 9, 5, 10, 6, 3, 7, 4 и 1. Применяя процедуру INORDER, получим список симметрично упорядоченных узлов этого же дерева: 2, 1, 8, 5, 9, 3, 10, 6, 7 и 4.

Слайд 21





Пример 3. Обратный и симметричный обходы дерева 
При обходе деревьев можно применить следующий полезный прием. Надо нарисовать непрерывный контур вокруг дерева, начиная от корня дерева, рисуя контур против часовой стрелки и поочередно обходя все наружные части дерева. 
При прямом упорядочивании узлов надо просто записать их в соответствии с нарисованным контуром.
Описание слайда:
Пример 3. Обратный и симметричный обходы дерева При обходе деревьев можно применить следующий полезный прием. Надо нарисовать непрерывный контур вокруг дерева, начиная от корня дерева, рисуя контур против часовой стрелки и поочередно обходя все наружные части дерева. При прямом упорядочивании узлов надо просто записать их в соответствии с нарисованным контуром.

Слайд 22





Помеченные деревья 
и деревья выражений 
Часто бывает полезным сопоставить каждому узлу дерева метку (label) или значение, точно так же, как мы в предыдущей теме сопоставляли элементам списков определенные значения. 
Дерево, у которого узлам сопоставлены метки, называется помеченным деревом. 
Метка узла - это не имя узла, а значение, которое "хранится" в узле. 
В некоторых приложениях требуется изменять значение метки, поскольку имя узла сохраняется постоянным. 
Полезна следующая аналогия: 
дерево-список, узел-позиция, метка-элемент.
Описание слайда:
Помеченные деревья и деревья выражений Часто бывает полезным сопоставить каждому узлу дерева метку (label) или значение, точно так же, как мы в предыдущей теме сопоставляли элементам списков определенные значения. Дерево, у которого узлам сопоставлены метки, называется помеченным деревом. Метка узла - это не имя узла, а значение, которое "хранится" в узле. В некоторых приложениях требуется изменять значение метки, поскольку имя узла сохраняется постоянным. Полезна следующая аналогия: дерево-список, узел-позиция, метка-элемент.

Слайд 23





Пример 4. Дерево выражения с метками
На рисунке показано дерево с метками, представляющее арифметическое выражение (а+b)*(а+с), где n1, ..., n7 - имена узлов (метки на рисунке проставлены рядом с соответствующими узлами). 
Правила соответствия меток деревьев элементам выражений следующие.
Описание слайда:
Пример 4. Дерево выражения с метками На рисунке показано дерево с метками, представляющее арифметическое выражение (а+b)*(а+с), где n1, ..., n7 - имена узлов (метки на рисунке проставлены рядом с соответствующими узлами). Правила соответствия меток деревьев элементам выражений следующие.

Слайд 24





Помеченные деревья 
и деревья выражений 
Часто при обходе деревьев составляется список не имен узлов, а их меток. 
В случае дерева выражений при прямом упорядочивании получаем известную префиксную форму выражений, где оператор предшествует и левому, и правому операндам. 
Для точного описания префиксной формы выражений сначала положим, что префиксным выражением одиночного операнда а является сам этот операнд. 
Далее, префиксная форма для выражения (E1)(Е2), где  - бинарный оператор, имеет вид P1P2, здесь P1, P2 - префиксные формы для выражений E1, Е2.
Описание слайда:
Помеченные деревья и деревья выражений Часто при обходе деревьев составляется список не имен узлов, а их меток. В случае дерева выражений при прямом упорядочивании получаем известную префиксную форму выражений, где оператор предшествует и левому, и правому операндам. Для точного описания префиксной формы выражений сначала положим, что префиксным выражением одиночного операнда а является сам этот операнд. Далее, префиксная форма для выражения (E1)(Е2), где  - бинарный оператор, имеет вид P1P2, здесь P1, P2 - префиксные формы для выражений E1, Е2.

Слайд 25





Помеченные деревья 
и деревья выражений 
Отметим, что в префиксных формах нет необходимости отделять или выделять отдельные префиксные выражения скобками, так как всегда можно просмотреть префиксное выражение P1P2 и определить единственным образом P1 как самый короткий префикс выражения P1P2. 
Например, при прямом упорядочивании узлов (точнее, меток) дерева, показанного на рис., получаем префиксное выражение *+ab+ac. Самым коротким корректным префиксом для выражения +ab+ac будет префиксное выражение узла n2: +ab.
Описание слайда:
Помеченные деревья и деревья выражений Отметим, что в префиксных формах нет необходимости отделять или выделять отдельные префиксные выражения скобками, так как всегда можно просмотреть префиксное выражение P1P2 и определить единственным образом P1 как самый короткий префикс выражения P1P2. Например, при прямом упорядочивании узлов (точнее, меток) дерева, показанного на рис., получаем префиксное выражение *+ab+ac. Самым коротким корректным префиксом для выражения +ab+ac будет префиксное выражение узла n2: +ab.

Слайд 26





Помеченные деревья 
и деревья выражений 
Обратное упорядочивание меток дерева выражений дает так называемое постфиксное представление выражений. 
Выражение P1P2 в постфиксной форме имеет вид P1P2, где P1, P2 - постфиксные формы для выражений Е1 и Е2 соответственно. 
При использовании постфиксной формы в применении скобок нет необходимости, поскольку для любого постфиксного выражения P1P2 легко проследить самый короткий суффикс P2, что и будет корректным составляющим постфиксным выражением. 
Например, постфиксная форма выражения для дерева на рис. имеет вид ab+ac+*. Если записать это выражение как P1P2*, то P2 (т.е. выражение ас+) будет самым коротким суффиксом для ab+ac+ и, следовательно, корректным составляющим постфиксным выражением.
Описание слайда:
Помеченные деревья и деревья выражений Обратное упорядочивание меток дерева выражений дает так называемое постфиксное представление выражений. Выражение P1P2 в постфиксной форме имеет вид P1P2, где P1, P2 - постфиксные формы для выражений Е1 и Е2 соответственно. При использовании постфиксной формы в применении скобок нет необходимости, поскольку для любого постфиксного выражения P1P2 легко проследить самый короткий суффикс P2, что и будет корректным составляющим постфиксным выражением. Например, постфиксная форма выражения для дерева на рис. имеет вид ab+ac+*. Если записать это выражение как P1P2*, то P2 (т.е. выражение ас+) будет самым коротким суффиксом для ab+ac+ и, следовательно, корректным составляющим постфиксным выражением.

Слайд 27





Помеченные деревья 
и деревья выражений 
При симметричном обходе дерева выражений получим так называемую инфиксную форму выражения, которая совпадает с привычной "стандартной" формой записи выражений, но также не использует скобок. Для дерева на рис. инфиксное выражение запишется как а+b * а+с. 
Таким образом, требуется разработать алгоритм обхода дерева выражений, который бы выдавал инфиксную форму выражения со всеми необходимыми парами скобок.
Описание слайда:
Помеченные деревья и деревья выражений При симметричном обходе дерева выражений получим так называемую инфиксную форму выражения, которая совпадает с привычной "стандартной" формой записи выражений, но также не использует скобок. Для дерева на рис. инфиксное выражение запишется как а+b * а+с. Таким образом, требуется разработать алгоритм обхода дерева выражений, который бы выдавал инфиксную форму выражения со всеми необходимыми парами скобок.

Слайд 28





Вычисление „наследственных" данных 
Обход дерева в прямом или обратном порядке позволяет получить данные об отношениях предок-потомок узлов дерева. 
Пусть функция postorder(n) вычисляет позицию узла n в списке узлов, упорядоченных в обратном порядке. Например, для узлов n2, n4 и n5 дерева, представленного на рис., значения этой функции будут 3, 1 и 2 соответственно. 
Определим также функцию desc(n), значение которой равно числу истинных потомков узла n.
Описание слайда:
Вычисление „наследственных" данных Обход дерева в прямом или обратном порядке позволяет получить данные об отношениях предок-потомок узлов дерева. Пусть функция postorder(n) вычисляет позицию узла n в списке узлов, упорядоченных в обратном порядке. Например, для узлов n2, n4 и n5 дерева, представленного на рис., значения этой функции будут 3, 1 и 2 соответственно. Определим также функцию desc(n), значение которой равно числу истинных потомков узла n.

Слайд 29





Вычисление „наследственных" данных 
Эти функции позволяют выполнить ряд полезных вычислений. 
Например, все узлы поддерева с корнем n будут последовательно занимать позиции от postorder(n)–desc(n) до postorder(n) в списке узлов, упорядоченных в обратном порядке. 
Для того чтобы узел х был потомком узла у, надо, чтобы выполнялись следующие неравенства: 
postorder(y)–desc(y) ≤ postorder(x) ≤ postorder(y). 
Подобные функции можно определить и для списков узлов, упорядоченных в прямом порядке.
Описание слайда:
Вычисление „наследственных" данных Эти функции позволяют выполнить ряд полезных вычислений. Например, все узлы поддерева с корнем n будут последовательно занимать позиции от postorder(n)–desc(n) до postorder(n) в списке узлов, упорядоченных в обратном порядке. Для того чтобы узел х был потомком узла у, надо, чтобы выполнялись следующие неравенства: postorder(y)–desc(y) ≤ postorder(x) ≤ postorder(y). Подобные функции можно определить и для списков узлов, упорядоченных в прямом порядке.

Слайд 30






Абстрактный тип данных TREE (дерево)
Описание слайда:
Абстрактный тип данных TREE (дерево)

Слайд 31






В теме 4 списки, стеки и очереди получили трактовку как абстрактные типы данных (АТД). В этой теме рассмотрим деревья как АТД и как структуры данных. 
Одно из наиболее важных применений деревьев – это использование их при разработке реализаций различных АТД. 
Далее мы покажем, как можно использовать "дерево двоичного поиска" при реализации АТД, основанных на математической модели множеств. Будут представлены примеры применения деревьев при реализации различных абстрактных типов данных. 
В этом разделе мы представим несколько полезных операторов, выполняемых над деревьями, и покажем, как использовать эти операторы в различных алгоритмах.
Описание слайда:
В теме 4 списки, стеки и очереди получили трактовку как абстрактные типы данных (АТД). В этой теме рассмотрим деревья как АТД и как структуры данных. Одно из наиболее важных применений деревьев – это использование их при разработке реализаций различных АТД. Далее мы покажем, как можно использовать "дерево двоичного поиска" при реализации АТД, основанных на математической модели множеств. Будут представлены примеры применения деревьев при реализации различных абстрактных типов данных. В этом разделе мы представим несколько полезных операторов, выполняемых над деревьями, и покажем, как использовать эти операторы в различных алгоритмах.

Слайд 32





Операторы, выполняемые 
над деревьями
1. PARENT(n, Т). 
Эта функция возвращает родителя (parent) узла n в дереве Т. 
Если n является корнем, который не имеет родителя, то в этом случае возвращается  ("нулевой узел“), что указывает на то, что мы выходим за пределы дерева. 
2. LEFTMOST_CHILD(n, Т). 
Данная функция возвращает самого левого сына узла n в 
дереве Т. Если n является листом (и поэтому не имеет сына), то возвращается .
Описание слайда:
Операторы, выполняемые над деревьями 1. PARENT(n, Т). Эта функция возвращает родителя (parent) узла n в дереве Т. Если n является корнем, который не имеет родителя, то в этом случае возвращается  ("нулевой узел“), что указывает на то, что мы выходим за пределы дерева. 2. LEFTMOST_CHILD(n, Т). Данная функция возвращает самого левого сына узла n в дереве Т. Если n является листом (и поэтому не имеет сына), то возвращается .

Слайд 33





Операторы, выполняемые 
над деревьями
3. RIGHT_SIBLING(n, Т). 
Эта функция возвращает правого брата узла n в дереве Т и значение , если такового не существует. Для этого находится родитель р узла n и все сыновья узла р, затем среди этих сыновей находится узел, расположенный непосредственно справа от узла n. 
Например, для дерева на рис.  
LEFTMOST_CHILD(n2) = n4, 
RIGHT_SIBLING(n4) = n5,
RIGHT_SIBLING(n5) = .
Описание слайда:
Операторы, выполняемые над деревьями 3. RIGHT_SIBLING(n, Т). Эта функция возвращает правого брата узла n в дереве Т и значение , если такового не существует. Для этого находится родитель р узла n и все сыновья узла р, затем среди этих сыновей находится узел, расположенный непосредственно справа от узла n. Например, для дерева на рис. LEFTMOST_CHILD(n2) = n4, RIGHT_SIBLING(n4) = n5, RIGHT_SIBLING(n5) = .

Слайд 34





Операторы, выполняемые 
над деревьями
4. LABEL(n, Т). 
Возвращает метку узла n дерева Т. Для выполнения этой функции требуется, чтобы на узлах дерева были определены метки. 
5. CREATEi(v, Т1, Т2, ..., Тi) 
это обширное семейство "созидающих" функций, которые для каждого i=0, 1, 2, ... создают новый корень r с меткой v и далее для этого корня создает i сыновей, которые становятся корнями поддеревьев Т1, Т2, ..., Тi. 
Эти функции возвращают дерево с корнем r. 
Для i=0 возвращается один узел r, который одновременно является и корнем, и листом.
Описание слайда:
Операторы, выполняемые над деревьями 4. LABEL(n, Т). Возвращает метку узла n дерева Т. Для выполнения этой функции требуется, чтобы на узлах дерева были определены метки. 5. CREATEi(v, Т1, Т2, ..., Тi) это обширное семейство "созидающих" функций, которые для каждого i=0, 1, 2, ... создают новый корень r с меткой v и далее для этого корня создает i сыновей, которые становятся корнями поддеревьев Т1, Т2, ..., Тi. Эти функции возвращают дерево с корнем r. Для i=0 возвращается один узел r, который одновременно является и корнем, и листом.

Слайд 35





Операторы, выполняемые 
над деревьями
6. ROOT(T). 
Возвращает узел, являющимся корнем дерева Т. Если Т - пустое дерево, то возвращается . 
7. MAKENULL(Т). 
Этот оператор делает дерево Т пустым деревом.
Описание слайда:
Операторы, выполняемые над деревьями 6. ROOT(T). Возвращает узел, являющимся корнем дерева Т. Если Т - пустое дерево, то возвращается . 7. MAKENULL(Т). Этот оператор делает дерево Т пустым деревом.

Слайд 36





Пример 5. 
Напишем рекурсивную PREORDER и нерекурсивную NPREORDER процедуры обхода дерева в прямом порядке и составления соответствующего списка его меток. 
Предположим, что для узлов определен тип данных node (узел), так же, как и для типа данных TREE (Дерево), причем АТД TREE определен для деревьев с метками, которые имеют тип данных labeltype (тип метки). 
В листинге 4.2 приведена рекурсивная процедура, которая по заданному узлу n создает список в прямом порядке меток поддерева, корнем которого является узел n. 
Для составления списка всех узлов дерева Т надо выполнить вызов PREORDER(ROOT(T)).
Описание слайда:
Пример 5. Напишем рекурсивную PREORDER и нерекурсивную NPREORDER процедуры обхода дерева в прямом порядке и составления соответствующего списка его меток. Предположим, что для узлов определен тип данных node (узел), так же, как и для типа данных TREE (Дерево), причем АТД TREE определен для деревьев с метками, которые имеют тип данных labeltype (тип метки). В листинге 4.2 приведена рекурсивная процедура, которая по заданному узлу n создает список в прямом порядке меток поддерева, корнем которого является узел n. Для составления списка всех узлов дерева Т надо выполнить вызов PREORDER(ROOT(T)).

Слайд 37





Листинг 4.2. Рекурсивная процедура обхода дерева в прямом порядке 
procedure   PREORDER ( n: node ); 
var   с: node; 
begin 
	print(LABEL(n, T) ) ; 
	c: = LEFTMOST_CHILD(n, Т) ; 
	while с <>  do begin 
		PREORDER(с); 
		с:= RIGHT_SIBLING(c, T) 
	end 
end; 		{ PREORDER }
Описание слайда:
Листинг 4.2. Рекурсивная процедура обхода дерева в прямом порядке procedure PREORDER ( n: node ); var с: node; begin print(LABEL(n, T) ) ; c: = LEFTMOST_CHILD(n, Т) ; while с <>  do begin PREORDER(с); с:= RIGHT_SIBLING(c, T) end end; { PREORDER }

Слайд 38





Пример 5. 
Теперь напишем нерекурсивную процедуру для печати узлов дерева в прямом порядке. 
Чтобы совершить обход дерева, используем стек S, чей тип данных STACK уже объявлен как "стек для узлов". 
Основная идея разрабатываемого алгоритма заключается в том, что, когда мы дошли до узла n, стек хранит путь от корня до этого узла, причем корень находится на "дне" стека, а узел n - в вершине стека. 
Один и подходов к реализации обхода дерева в прямом порядке показан на примере программы NPREORDER в листинге 4.3.
Описание слайда:
Пример 5. Теперь напишем нерекурсивную процедуру для печати узлов дерева в прямом порядке. Чтобы совершить обход дерева, используем стек S, чей тип данных STACK уже объявлен как "стек для узлов". Основная идея разрабатываемого алгоритма заключается в том, что, когда мы дошли до узла n, стек хранит путь от корня до этого узла, причем корень находится на "дне" стека, а узел n - в вершине стека. Один и подходов к реализации обхода дерева в прямом порядке показан на примере программы NPREORDER в листинге 4.3.

Слайд 39





Пример 5. 
Программа NPREORDER выполняет два вида операций, т.е. может находиться как бы в одном из двух режимов. 
Операции первого вида (первый режим) осуществляют обход по направлению к потомкам самого левого еще не проверенного пути дерева до тех пор, пока не встретится лист, при этом выполняется печать узлов этого пути и занесение их в стек. 
Во втором режиме выполнения программы осуществляется возврат по пройденному пути с поочередным извлечением узлов из стека до тех пор, пока не встретится узел, имеющий еще "не описанного" правого брата. Тогда программа опять переходит в первый режим и исследует новый путь, начиная с этого правого брата. 
Программа начинается в первом режиме с нахождения корня дерева и определения, является ли стек пустым.
Описание слайда:
Пример 5. Программа NPREORDER выполняет два вида операций, т.е. может находиться как бы в одном из двух режимов. Операции первого вида (первый режим) осуществляют обход по направлению к потомкам самого левого еще не проверенного пути дерева до тех пор, пока не встретится лист, при этом выполняется печать узлов этого пути и занесение их в стек. Во втором режиме выполнения программы осуществляется возврат по пройденному пути с поочередным извлечением узлов из стека до тех пор, пока не встретится узел, имеющий еще "не описанного" правого брата. Тогда программа опять переходит в первый режим и исследует новый путь, начиная с этого правого брата. Программа начинается в первом режиме с нахождения корня дерева и определения, является ли стек пустым.

Слайд 40





Листинг 4.3. Нерекурсивная процедура обхода дерева в прямом порядке 
procedure   NPREORDER ( T: TREE ); 
var  m: node;	       {переменная для временного хранения узлов} 
S: STACK;      {стек узлов, хранящий путь от корня до 
			родителя TOP(S) текущего узла m } 
begin 		{ инициализация } 
MAKENULL(S); 		m:= ROOT (T) ; 
while   true   do 
if   m <>    then   begin 
print(LABEL(m, T)); 	PUSH(m, S) ; 
{ исследование самого левого сына узла m } 
т:= LEFTMOST_CHILD(m, T) 
end 
else   begin 
{ завершена проверка пути, содержащегося в стеке } 
if   EMPTY(S)   then  return; 
{ исследование правого брата узла, находящегося в вершине стека } 
т:= RIGHT_SIBLING(TOP(S), T); 
POP(S) 
end 
end; 		{ NPREORDER }
Описание слайда:
Листинг 4.3. Нерекурсивная процедура обхода дерева в прямом порядке procedure NPREORDER ( T: TREE ); var m: node; {переменная для временного хранения узлов} S: STACK; {стек узлов, хранящий путь от корня до родителя TOP(S) текущего узла m } begin { инициализация } MAKENULL(S); m:= ROOT (T) ; while true do if m <>  then begin print(LABEL(m, T)); PUSH(m, S) ; { исследование самого левого сына узла m } т:= LEFTMOST_CHILD(m, T) end else begin { завершена проверка пути, содержащегося в стеке } if EMPTY(S) then return; { исследование правого брата узла, находящегося в вершине стека } т:= RIGHT_SIBLING(TOP(S), T); POP(S) end end; { NPREORDER }

Слайд 41






Реализация деревьев
Описание слайда:
Реализация деревьев

Слайд 42





Представление деревьев 
с помощью массивов 
Пусть Т - дерево с узлами 1, 2, ..., n. 
Возможно, самым простым представлением дерева Т, поддерживающим оператор PARENT (Родитель), будет линейный массив А, где каждый элемент А[i] является указателем или курсором на родителя узла i. 
Корень дерева Т отличается от других узлов тем, что имеет нулевой указатель или указатель на самого себя как на родителя. 
В языке Pascal указатели на элементы массива недопустимы, поэтому мы будем использовать схему с курсорами, тогда А[i]=j, если узел j является родителем узла i, и А[i]=0, если узел i является корнем.
Описание слайда:
Представление деревьев с помощью массивов Пусть Т - дерево с узлами 1, 2, ..., n. Возможно, самым простым представлением дерева Т, поддерживающим оператор PARENT (Родитель), будет линейный массив А, где каждый элемент А[i] является указателем или курсором на родителя узла i. Корень дерева Т отличается от других узлов тем, что имеет нулевой указатель или указатель на самого себя как на родителя. В языке Pascal указатели на элементы массива недопустимы, поэтому мы будем использовать схему с курсорами, тогда А[i]=j, если узел j является родителем узла i, и А[i]=0, если узел i является корнем.

Слайд 43





Представление деревьев 
с помощью массивов 
Дерево и курсоры на родителей: 
Данное представление использует то свойство деревьев, что каждый узел, отличный от корня, имеет только одного родителя. 
Используя это представление, родителя любого узла можно найти за фиксированное время. Прохождение по любому пути, т.е. переход по узлам от родителя к родителю, можно выполнить за время, пропорциональное количеству узлов пути. 
Для реализации оператора LABEL можно использовать другой массив L, в котором элемент L[i] будет хранить метку узла i, либо объявить элементы массива А записями, состоящими из целых чисел (курсоров) и меток.
Описание слайда:
Представление деревьев с помощью массивов Дерево и курсоры на родителей: Данное представление использует то свойство деревьев, что каждый узел, отличный от корня, имеет только одного родителя. Используя это представление, родителя любого узла можно найти за фиксированное время. Прохождение по любому пути, т.е. переход по узлам от родителя к родителю, можно выполнить за время, пропорциональное количеству узлов пути. Для реализации оператора LABEL можно использовать другой массив L, в котором элемент L[i] будет хранить метку узла i, либо объявить элементы массива А записями, состоящими из целых чисел (курсоров) и меток.

Слайд 44





Представление деревьев 
с помощью массивов 
Использование указателей или курсоров на родителей не помогает в реализации операторов, требующих информацию о сыновьях. 
Используя описанное представление, крайне тяжело для данного узла n найти его сыновей или определить его высоту. 
Кроме того, в этом случае невозможно определить порядок сыновей узла (т.е. какой сын находится правее или левее другого сына). Поэтому нельзя реализовать операторы, подобные LEFTMOST_CHILD и RIGHT_SIBLING.
Описание слайда:
Представление деревьев с помощью массивов Использование указателей или курсоров на родителей не помогает в реализации операторов, требующих информацию о сыновьях. Используя описанное представление, крайне тяжело для данного узла n найти его сыновей или определить его высоту. Кроме того, в этом случае невозможно определить порядок сыновей узла (т.е. какой сын находится правее или левее другого сына). Поэтому нельзя реализовать операторы, подобные LEFTMOST_CHILD и RIGHT_SIBLING.

Слайд 45





Представление деревьев 
с помощью массивов 
Можно ввести искусственный порядок нумерации узлов, например нумерацию сыновей в возрастающем порядке слева направо. Используя такую нумерацию, можно реализовать оператор RIGHT_SIBLING, код для этого оператора приведен в листинге 4.4. 
Для задания типов данных node (узел) и TREE (Дерево) используется следующее объявление: 
type  node = integer; 
		TREE = array [1..maxnodes] of node; 
В этой реализации мы предполагаем, что нулевой узел  представлен 0.
Описание слайда:
Представление деревьев с помощью массивов Можно ввести искусственный порядок нумерации узлов, например нумерацию сыновей в возрастающем порядке слева направо. Используя такую нумерацию, можно реализовать оператор RIGHT_SIBLING, код для этого оператора приведен в листинге 4.4. Для задания типов данных node (узел) и TREE (Дерево) используется следующее объявление: type node = integer; TREE = array [1..maxnodes] of node; В этой реализации мы предполагаем, что нулевой узел  представлен 0.

Слайд 46





Листинг 4.4. Оператор определения правого брата 
function  RIGHT_SIBLING ( n: node; T: TREE ) : node; 
var   i, parent: node; 
begin 
parent:= T[n] ; 
RIGHT_SIBLING:=0 	{ правый брат не найден }
for   i:=n+1  to   maxnodes  do 
	if  T[i]=parent  then 
		RIGHT_SIBLING:=i; 
end; 		{ RIGHT_SIBLING }
Описание слайда:
Листинг 4.4. Оператор определения правого брата function RIGHT_SIBLING ( n: node; T: TREE ) : node; var i, parent: node; begin parent:= T[n] ; RIGHT_SIBLING:=0 { правый брат не найден } for i:=n+1 to maxnodes do if T[i]=parent then RIGHT_SIBLING:=i; end; { RIGHT_SIBLING }

Слайд 47





Представление деревьев 
с помощью списков сыновей 
Важный и полезный способ представления деревьев состоит в формировании для каждого узла списка его сыновей. 
Эти списки можно представить любым методом, описанным в теме 3, но, так как число сыновей у разных узлов может быть разное, чаще всего для этих целей применяются связанные списки.
Описание слайда:
Представление деревьев с помощью списков сыновей Важный и полезный способ представления деревьев состоит в формировании для каждого узла списка его сыновей. Эти списки можно представить любым методом, описанным в теме 3, но, так как число сыновей у разных узлов может быть разное, чаще всего для этих целей применяются связанные списки.

Слайд 48





Представление деревьев 
с помощью списков сыновей 
На рис. показано, как таким способом представить следующее дерево: 
Здесь есть массив ячеек заголовков, индексированный номерами (они же имена) узлов. Каждый заголовок (header) указывает на связанный список, состоящий из "элементов"-узлов. Элементы списка header[i] являются сыновьями узла i, например узлы 9 и 10 - сыновья узла 3.
Описание слайда:
Представление деревьев с помощью списков сыновей На рис. показано, как таким способом представить следующее дерево: Здесь есть массив ячеек заголовков, индексированный номерами (они же имена) узлов. Каждый заголовок (header) указывает на связанный список, состоящий из "элементов"-узлов. Элементы списка header[i] являются сыновьями узла i, например узлы 9 и 10 - сыновья узла 3.

Слайд 49





Представление деревьев 
с помощью списков сыновей 
Прежде чем разрабатывать необходимую структуру данных, нам надо в терминах абстрактного типа данных LIST (список узлов) сделать отдельную реализацию списков сыновей и посмотреть, как эти абстракции согласуются между собой. Начнем со следующих объявлений типов: 
type   node = integer; 
	LIST= { соотв. определение для списка узлов } ; 
	position= { соотв. определение позиций в списках } ; 
	TREE = record 
			header: array[1..maxnodes]  of  LIST; 
			labels: array[1..maxnodes]  of  labeltype; 
			root: node 
	end; 
Мы предполагаем, что корень каждого дерева хранится отдельно в поле root (корень). Для обозначения нулевого узла используется 0. 
В листинге 4.5 представлен код функции LEFTMOST_CHILD.
Описание слайда:
Представление деревьев с помощью списков сыновей Прежде чем разрабатывать необходимую структуру данных, нам надо в терминах абстрактного типа данных LIST (список узлов) сделать отдельную реализацию списков сыновей и посмотреть, как эти абстракции согласуются между собой. Начнем со следующих объявлений типов: type node = integer; LIST= { соотв. определение для списка узлов } ; position= { соотв. определение позиций в списках } ; TREE = record header: array[1..maxnodes] of LIST; labels: array[1..maxnodes] of labeltype; root: node end; Мы предполагаем, что корень каждого дерева хранится отдельно в поле root (корень). Для обозначения нулевого узла используется 0. В листинге 4.5 представлен код функции LEFTMOST_CHILD.

Слайд 50





Листинг 4.5. Функция нахождения самого левого сына 
function   LEFTMOST_CHILD ( n: node; T: TREE ): node; 
{ возвращает самого левого сына узла n дерева Т } 
var  L: LIST;	 { скоропись для списка сыновей узла n } 
begin 
L:= T.header[n]; 
if  EMPTY(L)  then  	{ n является листом } 
LEFTMOST_CHILD:=0
else 
LEFTMOST_CHILD:= RETRIEVE(FIRST(L), L) 
end; 		{ LEFTMOST_CHILD }
Описание слайда:
Листинг 4.5. Функция нахождения самого левого сына function LEFTMOST_CHILD ( n: node; T: TREE ): node; { возвращает самого левого сына узла n дерева Т } var L: LIST; { скоропись для списка сыновей узла n } begin L:= T.header[n]; if EMPTY(L) then { n является листом } LEFTMOST_CHILD:=0 else LEFTMOST_CHILD:= RETRIEVE(FIRST(L), L) end; { LEFTMOST_CHILD }

Слайд 51





Представление деревьев 
с помощью списков сыновей 
Теперь представим конкретную реализацию списков, где типы LIST и position имеют тип целых чисел, последние используются как курсоры в массиве записей cellspace (область ячеек): 
var  cellspaсе: array[1..maxnodes]  of  record 
node: integer; 
next: integer 
end; 
Для упрощения реализации можно положить, что списки сыновей не имеют ячеек заголовков. Точнее, мы поместим T.header[n] непосредственно в первую ячейку списка, как показано на рисунке слайда 47. 
В листинге 4.6 представлен переписанный с учетом этого упрощения код функции LEFTMOST_CHILD, а также показан код функции PARENT, использующий данное представление списков. Эта функция более трудна для реализации, так как определение списка, в котором находится заданный узел, требует просмотра всех списков сыновей.
Описание слайда:
Представление деревьев с помощью списков сыновей Теперь представим конкретную реализацию списков, где типы LIST и position имеют тип целых чисел, последние используются как курсоры в массиве записей cellspace (область ячеек): var cellspaсе: array[1..maxnodes] of record node: integer; next: integer end; Для упрощения реализации можно положить, что списки сыновей не имеют ячеек заголовков. Точнее, мы поместим T.header[n] непосредственно в первую ячейку списка, как показано на рисунке слайда 47. В листинге 4.6 представлен переписанный с учетом этого упрощения код функции LEFTMOST_CHILD, а также показан код функции PARENT, использующий данное представление списков. Эта функция более трудна для реализации, так как определение списка, в котором находится заданный узел, требует просмотра всех списков сыновей.

Слайд 52





Листинг 4.6. Функции, использующие представление деревьев посредством связанных списков 
function   LEFTMOST_CHILD ( n: node; T: TREE ): node; 
{ возвращает самого левого сына узла n дерева Т } 
var  L: integer; 	{ курсор на начало списка сыновей узла n } 
begin 
L:= T.header[n]; 
if   L = 0   then  	{ n является листом } 
	LEFTMOST_CHILD:=0 
else 
LEFTMOST_CHILD:=сеllspace[L].node 
end; 			{ LEFTMOST_CHILD }
Описание слайда:
Листинг 4.6. Функции, использующие представление деревьев посредством связанных списков function LEFTMOST_CHILD ( n: node; T: TREE ): node; { возвращает самого левого сына узла n дерева Т } var L: integer; { курсор на начало списка сыновей узла n } begin L:= T.header[n]; if L = 0 then { n является листом } LEFTMOST_CHILD:=0 else LEFTMOST_CHILD:=сеllspace[L].node end; { LEFTMOST_CHILD }

Слайд 53





Листинг 4.6. Функции, использующие представление деревьев посредством связанных списков 
function   PARENT ( n: node; T: TREE ): node; 
{ возвращает родителя узла n дерева Т } 
var   р: node; 	{ пробегает возможных родителей узла n } 
         i: position; 	{ пробегает список сыновей p } 
begin 
PARENT:=0 	{ родитель не найден }
for  p:=1  to  maxnodes  do  begin 
i:= T.header [p]; 
while  i <> 0  do 	{ проверка на наличие сыновей узла р } 
if  cellspace[i].node = n  then  PARENT:=p 
else  i:= cellspace[i].next 
end; 
end; { PARENT }
Описание слайда:
Листинг 4.6. Функции, использующие представление деревьев посредством связанных списков function PARENT ( n: node; T: TREE ): node; { возвращает родителя узла n дерева Т } var р: node; { пробегает возможных родителей узла n } i: position; { пробегает список сыновей p } begin PARENT:=0 { родитель не найден } for p:=1 to maxnodes do begin i:= T.header [p]; while i <> 0 do { проверка на наличие сыновей узла р } if cellspace[i].node = n then PARENT:=p else i:= cellspace[i].next end; end; { PARENT }

Слайд 54





Представление через левых сыновей и правых братьев 
Среди прочих недостатков описанная выше структура данных не позволяет также с помощью операторов CREATEi создавать большие деревья из малых. 
Это является следствием того, что все деревья совместно используют массив cellspace для представления связанных списков сыновей; по сути, каждое дерево имеет собственный массив заголовков для своих узлов. А при реализации, например, оператора CREATE2(v, T1, Т2) надо скопировать деревья T1, Т2 в третье дерево и добавить новый узел с меткой v и двух его сыновей - корни деревьев T1, Т2. 
Если мы хотим построить большое дерево на основе нескольких малых, то желательно, чтобы все узлы всех деревьев располагались в одной общей области.
Описание слайда:
Представление через левых сыновей и правых братьев Среди прочих недостатков описанная выше структура данных не позволяет также с помощью операторов CREATEi создавать большие деревья из малых. Это является следствием того, что все деревья совместно используют массив cellspace для представления связанных списков сыновей; по сути, каждое дерево имеет собственный массив заголовков для своих узлов. А при реализации, например, оператора CREATE2(v, T1, Т2) надо скопировать деревья T1, Т2 в третье дерево и добавить новый узел с меткой v и двух его сыновей - корни деревьев T1, Т2. Если мы хотим построить большое дерево на основе нескольких малых, то желательно, чтобы все узлы всех деревьев располагались в одной общей области.

Слайд 55





Представление через левых сыновей и правых братьев 
Логическим продолжением представления дерева, показанного на слайде 47, будет замена массива заголовков на отдельный массив nodespace (область узлов), содержащий записи с произвольным местоположением в этом массиве. 
Содержимое поля header этих записей соответствует "номеру" узла, т.е. номеру записи в массиве cellspace. 
В свою очередь поле node массива cellspace теперь является курсором для массива nodespace, указывающим позицию узла. 
Тип TREE в этой ситуации просто курсор в массиве nodespace, указывающий позицию корня.
Описание слайда:
Представление через левых сыновей и правых братьев Логическим продолжением представления дерева, показанного на слайде 47, будет замена массива заголовков на отдельный массив nodespace (область узлов), содержащий записи с произвольным местоположением в этом массиве. Содержимое поля header этих записей соответствует "номеру" узла, т.е. номеру записи в массиве cellspace. В свою очередь поле node массива cellspace теперь является курсором для массива nodespace, указывающим позицию узла. Тип TREE в этой ситуации просто курсор в массиве nodespace, указывающий позицию корня.

Слайд 56





Пример представления через левых сыновей и правых братьев 
На рисунке показаны дерево и структура данных, где узлы этого дерева, помеченные как А, В, С и D, размещены в произвольных позициях массива nodespace. В массиве cellspace также в произвольном порядке размещены списки сыновей. 
Показанная на рисунке структура данных уже подходит для того, чтобы организовать слияние деревьев с помощью операторов CREATEi.
Описание слайда:
Пример представления через левых сыновей и правых братьев На рисунке показаны дерево и структура данных, где узлы этого дерева, помеченные как А, В, С и D, размещены в произвольных позициях массива nodespace. В массиве cellspace также в произвольном порядке размещены списки сыновей. Показанная на рисунке структура данных уже подходит для того, чтобы организовать слияние деревьев с помощью операторов CREATEi.

Слайд 57





Представление через левых сыновей и правых братьев 
Но и эту структуру можно значительно упростить. Для этого заметим, что цепочка указателей поля next массива cellspace перечисляет всех правых братьев. Используя эти указатели, можно найти самого левого сына следующим образом. 
Предположим, что cellspace[i].node = n. (Т.к. "имя" узла, в отличие от его метки, является индексом в массиве nodespace и этот индекс записан в поле cellspace[i].node.) 
Тогда указатель nodespace[n].header указывает на ячейку самого левого сына узла n в массиве cellspace, поскольку поле node этой ячейки является именем этого узла в массиве nodespace.
Описание слайда:
Представление через левых сыновей и правых братьев Но и эту структуру можно значительно упростить. Для этого заметим, что цепочка указателей поля next массива cellspace перечисляет всех правых братьев. Используя эти указатели, можно найти самого левого сына следующим образом. Предположим, что cellspace[i].node = n. (Т.к. "имя" узла, в отличие от его метки, является индексом в массиве nodespace и этот индекс записан в поле cellspace[i].node.) Тогда указатель nodespace[n].header указывает на ячейку самого левого сына узла n в массиве cellspace, поскольку поле node этой ячейки является именем этого узла в массиве nodespace.

Слайд 58





Представление через левых сыновей и правых братьев 
Можно упростить структуру, если идентифицировать узел не с помощью индекса в массиве nodespace, а с помощью индекса ячейки в массиве cellspace, который соответствует данному узлу как сыну. 
Тогда указатель next (переименуем это поле в right_sibling - правый брат) массива cellspace будет точно указывать на правого брата, а информацию, содержащуюся в массиве nodespace, можно перенести в новое поле leftmost_child (самый левый сын) массива cellspace. 
Здесь тип TREE является целочисленным типом и используется как курсор в массиве cellspace, указывающий на корень дерева.
Описание слайда:
Представление через левых сыновей и правых братьев Можно упростить структуру, если идентифицировать узел не с помощью индекса в массиве nodespace, а с помощью индекса ячейки в массиве cellspace, который соответствует данному узлу как сыну. Тогда указатель next (переименуем это поле в right_sibling - правый брат) массива cellspace будет точно указывать на правого брата, а информацию, содержащуюся в массиве nodespace, можно перенести в новое поле leftmost_child (самый левый сын) массива cellspace. Здесь тип TREE является целочисленным типом и используется как курсор в массиве cellspace, указывающий на корень дерева.

Слайд 59





Представление через левых сыновей и правых братьев 
Массив cellspace можно описать как следующую структуру: 
var   cellspace: array[1..maxnodes]  of  record 
label: labeltype; 
leftmost_child: integer; 
right_sibling: integer 
end;
Описание слайда:
Представление через левых сыновей и правых братьев Массив cellspace можно описать как следующую структуру: var cellspace: array[1..maxnodes] of record label: labeltype; leftmost_child: integer; right_sibling: integer end;

Слайд 60





Пример представления через левых сыновей и правых братьев 
Новое представление для дерева, схематически изображено на рис. Узлы дерева расположены в тех же ячейках массива, что и на слайде 55.
Описание слайда:
Пример представления через левых сыновей и правых братьев Новое представление для дерева, схематически изображено на рис. Узлы дерева расположены в тех же ячейках массива, что и на слайде 55.

Слайд 61





Представление через левых сыновей и правых братьев 
Используя описанное представление, все операторы, за исключением PARENT, можно реализовать путем прямых вычислений. Оператор PARENT требует просмотра всего массива cellspace. 
Если необходимо эффективное выполнение оператора PARENT, то можно добавить четвертое поле в массив cellspace для непосредственного указания на родителей. 
В качестве примера операторов, использующих структуры данных слайда 59, напишем код функции CREATE2, показанный в листинге 4.7.
Описание слайда:
Представление через левых сыновей и правых братьев Используя описанное представление, все операторы, за исключением PARENT, можно реализовать путем прямых вычислений. Оператор PARENT требует просмотра всего массива cellspace. Если необходимо эффективное выполнение оператора PARENT, то можно добавить четвертое поле в массив cellspace для непосредственного указания на родителей. В качестве примера операторов, использующих структуры данных слайда 59, напишем код функции CREATE2, показанный в листинге 4.7.

Слайд 62





Листинг 4.7. Функция CREATE2 
function   CREATE2 ( v: labeltype; T1, T2: integer ): integer; 
{ возвращает новое дерево с корнем v и поддеревьями T1 и T2 } 
var  temp: integer; { хранит индекс первой свободной ячейки 
			для корня нового дерева } 
begin 
temp;= avail; 
avail:= cellspace[avail].right_sibling; 
cellspace[temp].leftmost_child:= T1; 
cellspace[temp].label:= v; 
cellspace[temp].right_sibling:= 0; 
cellspace[T1].right_sibling:= T2; 
cellspace[T2].right_sibling:= 0;   {необязательный оператор} 
CREATE2:=temp 
end; 		{ CREATE2 }
Описание слайда:
Листинг 4.7. Функция CREATE2 function CREATE2 ( v: labeltype; T1, T2: integer ): integer; { возвращает новое дерево с корнем v и поддеревьями T1 и T2 } var temp: integer; { хранит индекс первой свободной ячейки для корня нового дерева } begin temp;= avail; avail:= cellspace[avail].right_sibling; cellspace[temp].leftmost_child:= T1; cellspace[temp].label:= v; cellspace[temp].right_sibling:= 0; cellspace[T1].right_sibling:= T2; cellspace[T2].right_sibling:= 0; {необязательный оператор} CREATE2:=temp end; { CREATE2 }

Слайд 63





Представление через левых сыновей и правых братьев 
Здесь мы предполагаем, что неиспользуемые ячейки массива cellspace связаны в один свободный список, который в листинге назван как avail, и ячейки этого списка связаны посредством поля right_sibling. 
На рис. показаны изменения указателей при выполнении функции CREATE2. Сплошные линии отображают старые указатели, а пунктирные линии - новые указатели в процессе создания нового дерева.
Описание слайда:
Представление через левых сыновей и правых братьев Здесь мы предполагаем, что неиспользуемые ячейки массива cellspace связаны в один свободный список, который в листинге назван как avail, и ячейки этого списка связаны посредством поля right_sibling. На рис. показаны изменения указателей при выполнении функции CREATE2. Сплошные линии отображают старые указатели, а пунктирные линии - новые указатели в процессе создания нового дерева.

Слайд 64






Двоичные деревья
Описание слайда:
Двоичные деревья

Слайд 65






Деревья, которые мы определили выше, называются упорядоченными ориентированными деревьями, поскольку сыновья любого узла упорядочены слева направо, а пути по дереву ориентированы от начального узла пути к его потомкам. 
Двоичное (или бинарное) дерево - совершенно другой вид. 
Двоичное дерево может быть или пустым деревом, или деревом, у которого любой узел или не имеет сыновей, или имеет либо левого сына, либо правого сына, либо обоих. 
Тот факт, что каждый сын любого узла определен как левый или как правый сын, существенно отличает двоичное дерево от упорядоченного ориентированного дерева.
Описание слайда:
Деревья, которые мы определили выше, называются упорядоченными ориентированными деревьями, поскольку сыновья любого узла упорядочены слева направо, а пути по дереву ориентированы от начального узла пути к его потомкам. Двоичное (или бинарное) дерево - совершенно другой вид. Двоичное дерево может быть или пустым деревом, или деревом, у которого любой узел или не имеет сыновей, или имеет либо левого сына, либо правого сына, либо обоих. Тот факт, что каждый сын любого узла определен как левый или как правый сын, существенно отличает двоичное дерево от упорядоченного ориентированного дерева.

Слайд 66





Пример 6. 
Если принять соглашение, что на схемах двоичных деревьев левый сын всегда соединяется с родителем линией, направленной влево и вниз от родителя, а правый сын - линией, направленной вправо и вниз, тогда на рис. 1, а, б представлены два различных дерева, хотя они оба похожи на обычное (упорядоченное ориентированное) дерево, показанное на рис. 2. 
Деревья на рис. 1,а, б различны и не эквивалентны дереву на рис. 2. 
		Рис. 1				Рис. 2
Описание слайда:
Пример 6. Если принять соглашение, что на схемах двоичных деревьев левый сын всегда соединяется с родителем линией, направленной влево и вниз от родителя, а правый сын - линией, направленной вправо и вниз, тогда на рис. 1, а, б представлены два различных дерева, хотя они оба похожи на обычное (упорядоченное ориентированное) дерево, показанное на рис. 2. Деревья на рис. 1,а, б различны и не эквивалентны дереву на рис. 2. Рис. 1 Рис. 2

Слайд 67






Обход двоичных деревьев в прямом и обратном порядке в точности соответствует таким же обходам обычных деревьев. 
При симметричном обходе двоичного дерева с корнем n левым поддеревом Т1 и правым поддеревом Т2 сначала проходится поддерево Т1 затем корень n и далее поддерево Т2. Например, симметричный обход дерева 
на рис. 1,а даст последовательность узлов 3, 5, 2, 4, 1.
Описание слайда:
Обход двоичных деревьев в прямом и обратном порядке в точности соответствует таким же обходам обычных деревьев. При симметричном обходе двоичного дерева с корнем n левым поддеревом Т1 и правым поддеревом Т2 сначала проходится поддерево Т1 затем корень n и далее поддерево Т2. Например, симметричный обход дерева на рис. 1,а даст последовательность узлов 3, 5, 2, 4, 1.

Слайд 68





Представление двоичных деревьев 
Если именами узлов двоичного дерева являются их номера 1, 2, ..., n, то подходящей структурой для представления этого дерева может служить массив cellspace записей с полями leftchild (левый сын) и rightchild (правый сын), объявленный следующим образом: 
var 
cellspace: array[1..maxnodes] of record 
leftchild: integer; 
rightchild: integer 
end; 
В этом представлении cellspace[i].leftchild является левым сыном узла i, a cellspace[i].rightchild - правым сыном. Значение 0 в обоих полях указывает на то, что узел i не имеет сыновей.
Описание слайда:
Представление двоичных деревьев Если именами узлов двоичного дерева являются их номера 1, 2, ..., n, то подходящей структурой для представления этого дерева может служить массив cellspace записей с полями leftchild (левый сын) и rightchild (правый сын), объявленный следующим образом: var cellspace: array[1..maxnodes] of record leftchild: integer; rightchild: integer end; В этом представлении cellspace[i].leftchild является левым сыном узла i, a cellspace[i].rightchild - правым сыном. Значение 0 в обоих полях указывает на то, что узел i не имеет сыновей.

Слайд 69





Представление двоичных деревьев 
Двоичное дерево: 	         Представление двоичного дерева:
Описание слайда:
Представление двоичных деревьев Двоичное дерево: Представление двоичного дерева:

Слайд 70





Коды Хаффмана 
Приведем пример применения двоичных деревьев в качестве структур данных. Для этого рассмотрим задачу конструирования кодов Хаффмана. 
Предположим, мы имеем сообщения, состоящие из последовательности символов. В каждом сообщении символы независимы и появляются с известной вероятностью, не зависящей от позиции в сообщении. 
Например, мы имеем сообщения, состоящие из пяти символов 
а, b, с, d, e,
которые появляются в сообщениях с вероятностями 
0.12, 0.4, 0.15, 0.08 и 0.25 
соответственно. 
Мы хотим закодировать каждый символ последовательностью из нулей и единиц так, чтобы код любого символа являлся префиксом кода сообщения, состоящего из последующих символов. Это префиксное свойство позволяет декодировать строку из нулей и единиц последовательным удалением префиксов (т.е. кодов символов) из этой строки.
Описание слайда:
Коды Хаффмана Приведем пример применения двоичных деревьев в качестве структур данных. Для этого рассмотрим задачу конструирования кодов Хаффмана. Предположим, мы имеем сообщения, состоящие из последовательности символов. В каждом сообщении символы независимы и появляются с известной вероятностью, не зависящей от позиции в сообщении. Например, мы имеем сообщения, состоящие из пяти символов а, b, с, d, e, которые появляются в сообщениях с вероятностями 0.12, 0.4, 0.15, 0.08 и 0.25 соответственно. Мы хотим закодировать каждый символ последовательностью из нулей и единиц так, чтобы код любого символа являлся префиксом кода сообщения, состоящего из последующих символов. Это префиксное свойство позволяет декодировать строку из нулей и единиц последовательным удалением префиксов (т.е. кодов символов) из этой строки.

Слайд 71





Коды Хаффмана 
В таблице показаны две возможные кодировки для наших пяти символов. 
Ясно, что первый код обладает префиксным свойством, поскольку любая последовательность из трех битов будет префиксом для другой последовательности из трех битов; другими словами, любая префиксная последовательность однозначно идентифицируется символом. 
Алгоритм декодирования для этого кода очень прост: 
надо поочередно брать по три бита и преобразовать каждую группу битов в соответствующие символы. 
Например, последовательность 001010011 соответствует исходному сообщению bed.
Описание слайда:
Коды Хаффмана В таблице показаны две возможные кодировки для наших пяти символов. Ясно, что первый код обладает префиксным свойством, поскольку любая последовательность из трех битов будет префиксом для другой последовательности из трех битов; другими словами, любая префиксная последовательность однозначно идентифицируется символом. Алгоритм декодирования для этого кода очень прост: надо поочередно брать по три бита и преобразовать каждую группу битов в соответствующие символы. Например, последовательность 001010011 соответствует исходному сообщению bed.

Слайд 72





Коды Хаффмана 
Задача конструирования кодов Хаффмана заключается в следующем: 
имея множество символов и значения вероятностей их появления в сообщениях, построить такой код с префиксным свойством, чтобы средняя длина кода (в вероятностном смысле) последовательности символов была минимальной. 
Мы хотим минимизировать среднюю длину кода для того, чтобы уменьшить длину вероятного сообщения (т.е. чтобы сжать сообщение). Чем короче среднее значение длины кода символов, тем короче закодированное сообщение.
Описание слайда:
Коды Хаффмана Задача конструирования кодов Хаффмана заключается в следующем: имея множество символов и значения вероятностей их появления в сообщениях, построить такой код с префиксным свойством, чтобы средняя длина кода (в вероятностном смысле) последовательности символов была минимальной. Мы хотим минимизировать среднюю длину кода для того, чтобы уменьшить длину вероятного сообщения (т.е. чтобы сжать сообщение). Чем короче среднее значение длины кода символов, тем короче закодированное сообщение.

Слайд 73





Коды Хаффмана 
В частности, первый код из примера слайда 71 имеет среднюю длину кода 3. Это число получается в результате умножения длины кода каждого символа на вероятность появления этого символа. 
Второй код имеет среднюю длину 2.2, поскольку символы а и d имеют суммарную вероятность появления 0.20 и длина их кода составляет три бита, тогда как другие символы имеют код длиной 21. 
Отсюда следует очевидный вывод, что 
символы с большими вероятностями появления должны иметь самые короткие коды.
Описание слайда:
Коды Хаффмана В частности, первый код из примера слайда 71 имеет среднюю длину кода 3. Это число получается в результате умножения длины кода каждого символа на вероятность появления этого символа. Второй код имеет среднюю длину 2.2, поскольку символы а и d имеют суммарную вероятность появления 0.20 и длина их кода составляет три бита, тогда как другие символы имеют код длиной 21. Отсюда следует очевидный вывод, что символы с большими вероятностями появления должны иметь самые короткие коды.

Слайд 74





Коды Хаффмана 
Можно ли придумать код, который был бы лучше второго кода? 
Ответ положительный: существует код с префиксным свойством, средняя длина которого равна 2.15. 
Это наилучший возможный код с теми же вероятностями появления символов.
Описание слайда:
Коды Хаффмана Можно ли придумать код, который был бы лучше второго кода? Ответ положительный: существует код с префиксным свойством, средняя длина которого равна 2.15. Это наилучший возможный код с теми же вероятностями появления символов.

Слайд 75





Коды Хаффмана 
Способ нахождения оптимального префиксного кода называется алгоритмом Хаффмана: 
Находятся два символа а и b с наименьшими вероятностями появления и заменяются одним фиктивным символом, например х, который имеет вероятность появления, равную сумме вероятностей появления символов a и b. 
Используя эту процедуру рекурсивно, находим оптимальный префиксный код для меньшего множества символов (где символы а и b заменены одним символом х). Код для исходного множества символов получается из кодов замещающих символов путем добавления 0 и 1 перед кодом замещающего символа, и эти два новых кода принимаются как коды заменяемых символов. 
Например, код символа а будет соответствовать коду символа х с добавленным нулем перед этим кодом, а для кода символа b перед кодом символа х будет добавлена единица.
Описание слайда:
Коды Хаффмана Способ нахождения оптимального префиксного кода называется алгоритмом Хаффмана: Находятся два символа а и b с наименьшими вероятностями появления и заменяются одним фиктивным символом, например х, который имеет вероятность появления, равную сумме вероятностей появления символов a и b. Используя эту процедуру рекурсивно, находим оптимальный префиксный код для меньшего множества символов (где символы а и b заменены одним символом х). Код для исходного множества символов получается из кодов замещающих символов путем добавления 0 и 1 перед кодом замещающего символа, и эти два новых кода принимаются как коды заменяемых символов. Например, код символа а будет соответствовать коду символа х с добавленным нулем перед этим кодом, а для кода символа b перед кодом символа х будет добавлена единица.

Слайд 76





Коды Хаффмана 
Можно рассматривать префиксные коды как пути на двоичном дереве:
прохождение от узла к его левому сыну соответствует 0 в коде, а к правому сыну - 1. 
Если мы пометим листья дерева кодируемыми символами, то получим представление префиксного кода в виде двоичного дерева. 
Префиксное свойство гарантирует, что нет символов, которые были бы метками внутренних узлов дерева (не листьев). 
И наоборот, помечая кодируемыми символами только листья дерева, мы обеспечиваем префиксное свойство кода этих символов.
Описание слайда:
Коды Хаффмана Можно рассматривать префиксные коды как пути на двоичном дереве: прохождение от узла к его левому сыну соответствует 0 в коде, а к правому сыну - 1. Если мы пометим листья дерева кодируемыми символами, то получим представление префиксного кода в виде двоичного дерева. Префиксное свойство гарантирует, что нет символов, которые были бы метками внутренних узлов дерева (не листьев). И наоборот, помечая кодируемыми символами только листья дерева, мы обеспечиваем префиксное свойство кода этих символов.

Слайд 77





Коды Хаффмана 
Двоичные деревья для кодов 1 и 2:
Описание слайда:
Коды Хаффмана Двоичные деревья для кодов 1 и 2:

Слайд 78





Коды Хаффмана 
Для реализации алгоритма Хаффмана мы используем лес, т.е. совокупность деревьев, чьи листья будут помечены символами, для которых разрабатывается кодировка, а корни помечены суммой вероятностей всех символов, соответствующих листьям дерева. Мы будем называть эти суммарные вероятности весом дерева. 
Вначале каждому символу соответствует дерево, состоящее из одного узла, в конце работы алгоритма мы получим одно дерево, все листья которого будут помечены кодируемыми символами. 
В этом дереве путь от корня к любому листу представляет код для символа-метки этого листа, составленный по схеме, согласно которой левый сын узла соответствует 0, а правый - 1 (как на рис. слайда 76).
Описание слайда:
Коды Хаффмана Для реализации алгоритма Хаффмана мы используем лес, т.е. совокупность деревьев, чьи листья будут помечены символами, для которых разрабатывается кодировка, а корни помечены суммой вероятностей всех символов, соответствующих листьям дерева. Мы будем называть эти суммарные вероятности весом дерева. Вначале каждому символу соответствует дерево, состоящее из одного узла, в конце работы алгоритма мы получим одно дерево, все листья которого будут помечены кодируемыми символами. В этом дереве путь от корня к любому листу представляет код для символа-метки этого листа, составленный по схеме, согласно которой левый сын узла соответствует 0, а правый - 1 (как на рис. слайда 76).

Слайд 79





Коды Хаффмана 
Важным этапом в работе алгоритма является выбор из леса двух деревьев с наименьшими весами. 
Эти два дерева комбинируются в одно с весом, равным сумме весов составляющих деревьев. При слиянии деревьев создается новый узел, который становится корнем объединенного дерева и который имеет в качестве левого и правого сыновей корни старых деревьев. 
Этот процесс продолжается до тех пор, пока не получится только одно дерево. Это дерево соответствует коду, который при заданных вероятностях имеет минимально возможную среднюю длину.
Описание слайда:
Коды Хаффмана Важным этапом в работе алгоритма является выбор из леса двух деревьев с наименьшими весами. Эти два дерева комбинируются в одно с весом, равным сумме весов составляющих деревьев. При слиянии деревьев создается новый узел, который становится корнем объединенного дерева и который имеет в качестве левого и правого сыновей корни старых деревьев. Этот процесс продолжается до тех пор, пока не получится только одно дерево. Это дерево соответствует коду, который при заданных вероятностях имеет минимально возможную среднюю длину.

Слайд 80





Этапы создания дерева Хаффмана
Описание слайда:
Этапы создания дерева Хаффмана

Слайд 81





Коды Хаффмана 
Теперь опишем необходимые структуры данных. 
Во-первых, для представления двоичных деревьев мы будем использовать массив TREE (Дерево), состоящий из записей следующего типа: 
record 
leftchild: integer; 
rightchild: integer; 
parent: integer 
end 
Указатели в поле parent (родитель) облегчают поиск путей от листа к корню при записи кода символов.
Описание слайда:
Коды Хаффмана Теперь опишем необходимые структуры данных. Во-первых, для представления двоичных деревьев мы будем использовать массив TREE (Дерево), состоящий из записей следующего типа: record leftchild: integer; rightchild: integer; parent: integer end Указатели в поле parent (родитель) облегчают поиск путей от листа к корню при записи кода символов.

Слайд 82





Коды Хаффмана 
Во-вторых, мы используем массив ALPHABET (Алфавит), также состоящий из записей, которые имеют следующий тип: 
record 
symbol: char; 
probability: real; 
leaf: integer 	{ курсор } 
end 
В этом массиве каждому символу (поле symbol), подлежащему кодированию, ставится, в соответствие вероятность его появления (поле probability) и лист, меткой которого он является (поле leaf).
Описание слайда:
Коды Хаффмана Во-вторых, мы используем массив ALPHABET (Алфавит), также состоящий из записей, которые имеют следующий тип: record symbol: char; probability: real; leaf: integer { курсор } end В этом массиве каждому символу (поле symbol), подлежащему кодированию, ставится, в соответствие вероятность его появления (поле probability) и лист, меткой которого он является (поле leaf).

Слайд 83





Коды Хаффмана 
В-третьих, для представления непосредственно деревьев необходим массив FOREST (Лес). Этот массив будет состоять из записей с полями 
weight (вес) и root (корень) 
следующего типа: 
record 
weight: real; 
root: integer 
end
Описание слайда:
Коды Хаффмана В-третьих, для представления непосредственно деревьев необходим массив FOREST (Лес). Этот массив будет состоять из записей с полями weight (вес) и root (корень) следующего типа: record weight: real; root: integer end

Слайд 84





Коды Хаффмана 
Начальные значения всех трех массивов, соответствующих данным на рисунке а показаны ниже.
Описание слайда:
Коды Хаффмана Начальные значения всех трех массивов, соответствующих данным на рисунке а показаны ниже.

Слайд 85





Листинг 4.8. Программа построения дерева Хаффмана 
(1) while  существует более одного дерева в лесу do  begin 
(2) 	i:= индекс дерева в FOREST с наименьшим весом; 
(3) 	j:= индекс дерева в FOREST со вторым наименьшим 		весом; 
(4) 	Создание нового узла с левым сыном FOREST[i].root 		и правым сыном FOREST[j].root; 
(5) 	Замена в FOREST дерева i деревом, чьим корнем 			является новый узел и чей вес равен 
		FOREST[i].weight + FOREST[j].weight; 
(6) 	Удаление дерева j из массива FOREST 
end;
Описание слайда:
Листинг 4.8. Программа построения дерева Хаффмана (1) while существует более одного дерева в лесу do begin (2) i:= индекс дерева в FOREST с наименьшим весом; (3) j:= индекс дерева в FOREST со вторым наименьшим весом; (4) Создание нового узла с левым сыном FOREST[i].root и правым сыном FOREST[j].root; (5) Замена в FOREST дерева i деревом, чьим корнем является новый узел и чей вес равен FOREST[i].weight + FOREST[j].weight; (6) Удаление дерева j из массива FOREST end;

Слайд 86





Листинг 4.8. Программа построения дерева Хаффмана 
Для реализации строки (4) листинга 4.8, где увеличивается количество используемых ячеек массива TREE, и строк (5) и (6), где уменьшается количество ячеек массива FOREST, мы будем использовать курсоры lasttree (последнее дерево) и lastnode (последний узел), указывающие соответственно на массив FOREST и массив TREE. 
Предполагается, что эти курсоры располагаются в первых ячейках соответствующих массивов. 
Для этапа чтения данных, который мы опускаем, необходим также курсор для массива ALPHABET, который бы "следил" за заполнением данными этого массива. 
Мы также предполагаем, что все массивы имеют определенную объявленную длину, но здесь мы не будем проводить сравнение этих ограничивающих значений со значениями курсоров.
Описание слайда:
Листинг 4.8. Программа построения дерева Хаффмана Для реализации строки (4) листинга 4.8, где увеличивается количество используемых ячеек массива TREE, и строк (5) и (6), где уменьшается количество ячеек массива FOREST, мы будем использовать курсоры lasttree (последнее дерево) и lastnode (последний узел), указывающие соответственно на массив FOREST и массив TREE. Предполагается, что эти курсоры располагаются в первых ячейках соответствующих массивов. Для этапа чтения данных, который мы опускаем, необходим также курсор для массива ALPHABET, который бы "следил" за заполнением данными этого массива. Мы также предполагаем, что все массивы имеют определенную объявленную длину, но здесь мы не будем проводить сравнение этих ограничивающих значений со значениями курсоров.

Слайд 87





Коды Хаффмана 
В листинге 4.9 приведены коды двух полезных процедур. 
Процедура lightones, выполняет реализацию строк (2) и (3) листинга 4.8 по выбору индексов двух деревьев с наименьшими весами. 
Функция create(n1, n2), создает новый узел и делает заданные узлы n1 и n2 левым и правым сыновьями этого узла.
Описание слайда:
Коды Хаффмана В листинге 4.9 приведены коды двух полезных процедур. Процедура lightones, выполняет реализацию строк (2) и (3) листинга 4.8 по выбору индексов двух деревьев с наименьшими весами. Функция create(n1, n2), создает новый узел и делает заданные узлы n1 и n2 левым и правым сыновьями этого узла.

Слайд 88





Листинг 4.9. 
procedure  lightones ( var  least, second: integer ); 
	{ присваивает переменным least и second индексы массива
	 FOREST, соответствующие деревьям с наименьшими весами.
	Предполагается, что lasttree > 2. } 
var   i: integer; 
begin { инициализация least и second, рассм-ся первые два дерева } 
    if   FOREST[1].weight <= F0REST[2].weight   then  begin 
		least:= 1;  	second:= 2 	end 
   else   begin 
		least:= 2; 	second:= 1 	end 
		for   i:= 3  to   lasttree   do 
	if   FOREST[i].weight < FOREST[least].weight  then 
begin 
			second:= least; 	least:= i 	end 
   else 
		if  FOREST[i].weight < FOREST[second].weight then 
				second:= i 
end; 		{ lightones }
Описание слайда:
Листинг 4.9. procedure lightones ( var least, second: integer ); { присваивает переменным least и second индексы массива FOREST, соответствующие деревьям с наименьшими весами. Предполагается, что lasttree > 2. } var i: integer; begin { инициализация least и second, рассм-ся первые два дерева } if FOREST[1].weight <= F0REST[2].weight then begin least:= 1; second:= 2 end else begin least:= 2; second:= 1 end for i:= 3 to lasttree do if FOREST[i].weight < FOREST[least].weight then begin second:= least; least:= i end else if FOREST[i].weight < FOREST[second].weight then second:= i end; { lightones }

Слайд 89





Листинг 4.9. 
function   create ( lefttree, righttree: integer ): integer; 
{ возвращает новый узел, у которого левым и правым сыновьями 
становятся FOREST[lefttree].root и FOREST[righttree].root } 
begin 
   lastnode:= lastnode + 1; 
   { ячейка TREE[lastnode] для нового узла } 
   TREE[lastnode].leftchild:= FOREST[lefttree].root; 
   TREE[lastnode].rightchild:= FOREST[righttree].root; 
   { теперь введем указатели для нового узла и его сыновей } 
   TREE[lastnode].parent:= 0; 
   TREE[FOREST[lefttree].root].parent:= lastnode; 
   TREE[FOREST[righttree].root].parent:= lastnode; 
   create:=lastnode 
end; 			{ create }
Описание слайда:
Листинг 4.9. function create ( lefttree, righttree: integer ): integer; { возвращает новый узел, у которого левым и правым сыновьями становятся FOREST[lefttree].root и FOREST[righttree].root } begin lastnode:= lastnode + 1; { ячейка TREE[lastnode] для нового узла } TREE[lastnode].leftchild:= FOREST[lefttree].root; TREE[lastnode].rightchild:= FOREST[righttree].root; { теперь введем указатели для нового узла и его сыновей } TREE[lastnode].parent:= 0; TREE[FOREST[lefttree].root].parent:= lastnode; TREE[FOREST[righttree].root].parent:= lastnode; create:=lastnode end; { create }

Слайд 90





Коды Хаффмана 
Теперь все неформальные операторы листинга 4.8 можно описать подробнее. 
В листинге 4.10 приведен код процедуры Huffman, которая не осуществляет ввод и вывод, а работает со структурами, показанными на рис. слайда 83, которые объявлены как глобальные.
Описание слайда:
Коды Хаффмана Теперь все неформальные операторы листинга 4.8 можно описать подробнее. В листинге 4.10 приведен код процедуры Huffman, которая не осуществляет ввод и вывод, а работает со структурами, показанными на рис. слайда 83, которые объявлены как глобальные.

Слайд 91





Листинг 4.10. Реализация алгоритма Хаффмана 
procedure Huffman; 
var  i, j:integer; {два дерева с наименьшими весами из FOREST } 
	newroot: integer; 
begin 
while  lasttree > 1  do  begin 
lightones(i, j); 
newroot:= create(i, j); 
{ далее дерево i заменяется деревом с корнем newroot } 
FOREST[i].weight:=FOREST[i].weight +FOREST[j].weight; 
FOREST[i].root:= newroot; 
{ далее дерево j заменяется на дерево lasttree, 
массив FOREST уменьшается на одну запись } 
FOREST[j]:= FOREST[lasttree] ; 
lasttree:= lasttree - 1 
end 
end; 			{ Huffman }
Описание слайда:
Листинг 4.10. Реализация алгоритма Хаффмана procedure Huffman; var i, j:integer; {два дерева с наименьшими весами из FOREST } newroot: integer; begin while lasttree > 1 do begin lightones(i, j); newroot:= create(i, j); { далее дерево i заменяется деревом с корнем newroot } FOREST[i].weight:=FOREST[i].weight +FOREST[j].weight; FOREST[i].root:= newroot; { далее дерево j заменяется на дерево lasttree, массив FOREST уменьшается на одну запись } FOREST[j]:= FOREST[lasttree] ; lasttree:= lasttree - 1 end end; { Huffman }

Слайд 92





Коды Хаффмана 
На рисунке показана структура данных из рис. слайда 83 после двух итераций, т.е. после того, как значение переменной lasttree уменьшено до 3, т.е. лес имеет вид, показанный на рис. слайда 79, в.
Описание слайда:
Коды Хаффмана На рисунке показана структура данных из рис. слайда 83 после двух итераций, т.е. после того, как значение переменной lasttree уменьшено до 3, т.е. лес имеет вид, показанный на рис. слайда 79, в.

Слайд 93





Коды Хаффмана 
После завершения работы алгоритма код каждого символа можно определить следующим образом. 
Найдем в массиве ALPHABET запись с нужным символ в поле symbol. 
Затем по значению поля leaf этой же записи определим местоположение записи в массиве TREE, которая соответствует листу, помеченному рассматриваемым символом. 
Далее последовательно переходим по указателю parent от текущей записи, например соответствующей узлу n, к записи в массиве TREE, соответствующей его родителю р. 
По родителю р определяем, в каком его поле, leftchild или rightchild, находится указатель на узел n, т.е. является ли узел n левым или правым сыном, и в соответствии с этим печатаем 0 (для левого сына) или 1 (для правого сына). 
Затем переходим к родителю узла р и определяем, является ли его сын р правым или левым, и в соответствии с эти печатаем следующую 1 или 0, и т. д. до самого корня дерева.
Описание слайда:
Коды Хаффмана После завершения работы алгоритма код каждого символа можно определить следующим образом. Найдем в массиве ALPHABET запись с нужным символ в поле symbol. Затем по значению поля leaf этой же записи определим местоположение записи в массиве TREE, которая соответствует листу, помеченному рассматриваемым символом. Далее последовательно переходим по указателю parent от текущей записи, например соответствующей узлу n, к записи в массиве TREE, соответствующей его родителю р. По родителю р определяем, в каком его поле, leftchild или rightchild, находится указатель на узел n, т.е. является ли узел n левым или правым сыном, и в соответствии с этим печатаем 0 (для левого сына) или 1 (для правого сына). Затем переходим к родителю узла р и определяем, является ли его сын р правым или левым, и в соответствии с эти печатаем следующую 1 или 0, и т. д. до самого корня дерева.

Слайд 94





Коды Хаффмана 
Таким образом, код символа будет напечатан в виде последовательности битов, но в обратном порядке. Чтобы распечатать эту последовательность в прямом порядке, надо каждый очередной бит помещать в стек, а затем распечатать содержимое стека в обычном порядке.
Описание слайда:
Коды Хаффмана Таким образом, код символа будет напечатан в виде последовательности битов, но в обратном порядке. Чтобы распечатать эту последовательность в прямом порядке, надо каждый очередной бит помещать в стек, а затем распечатать содержимое стека в обычном порядке.

Слайд 95





Реализация двоичных деревьев с помощью указателей 
Для указания на правых и левых сыновей (и родителей, если необходимо) вместо курсоров можно использовать настоящие указатели языка Pascal. Например, можно сделать объявление 
type   node = record 
leftchild: ^ node; 
rightchild: ^ node; 
parent: ^ node 
end 

Используя этот тип данных узлов двоичного дерева, функцию create (листинг 4.9) можно переписать так, как показано в следующем листинге 4.11.
Описание слайда:
Реализация двоичных деревьев с помощью указателей Для указания на правых и левых сыновей (и родителей, если необходимо) вместо курсоров можно использовать настоящие указатели языка Pascal. Например, можно сделать объявление type node = record leftchild: ^ node; rightchild: ^ node; parent: ^ node end Используя этот тип данных узлов двоичного дерева, функцию create (листинг 4.9) можно переписать так, как показано в следующем листинге 4.11.

Слайд 96





Листинг 4.11. Функция create 
при реализации двоичного дерева с помощью указателей 
function  create ( lefttree, righttree: ^node): ^node; 
var   root: ^node; 
begin 
new(root) ; 
root^.leftchild:= lefttree; 
root^.rightchild:= righttree; 
root^.parent:= 0; 
lefttree^.parent:= root; 
righttree^.parent:= root; 
create:=root 
end; 			{ create }
Описание слайда:
Листинг 4.11. Функция create при реализации двоичного дерева с помощью указателей function create ( lefttree, righttree: ^node): ^node; var root: ^node; begin new(root) ; root^.leftchild:= lefttree; root^.rightchild:= righttree; root^.parent:= 0; lefttree^.parent:= root; righttree^.parent:= root; create:=root end; { create }



Похожие презентации
Mypresentation.ru
Загрузить презентацию