Лекция_24 Деревья.pptx
- Количество слайдов: 79
Лекция 24 1 декабря 2009 года Тема: Структуры данных. Деревья. 1
Определение графа Неориентированный граф G — это упорядоченная пара G = (V, E), где V – конечное множество вершин или узлов; E - множество неупорядоченных пар различных вершин, называемых рёбрами. Вершины u и v называются концевыми вершинами ребра e = (u, v). Два ребра называются смежными, если они имеют общую концевую вершину. Если пары множества E упорядочены, то граф является ориентированным, а элементы множества E – дугами. 2
В неориентированном графе (v, w)=(w, v). Путь – это последовательность ребер вида (v 1, v 2), (v 3, v 4), …, (vn-1, vn). Говорят, что этот путь идет из вершины v 1 в вершину vn и имеет длину n-1. Часто его обозначают как последовательность вершин v 1, v 2, v 3, v 4, …, vn-1, vn. Тогда Путь - конечная последовательность вершин, в которой каждая вершина (кроме последней) соединена со следующей в последовательности вершин ребром. 3
Путь называется простым, если все ребра и все узлы на нем , кроме, может быть, первого и последнего, различны. 4
5
Определение дерева Дерево — связный (ориентированный или неориентированный) граф, не содержащий циклов (для любой вершины есть один и только один способ добраться до любой другой вершины) Неориентированное дерево Ориентированное дерево 6
Корневое дерево определяется как конечное множество T одного или более узлов со следующими свойствами: существует один корень дерева T ; остальные узлы (за исключением корня) распределены среди непересекающихся множеств T 1, . . . , Tm, и каждое из множеств является деревом; деревья T 1, . . . , Tm называются поддеревьями корня T 7
Определения, связанные с деревьями Степень узла — количество поддеревьев узла. Концевой узел (лист) — узел со степенью нуль. Уровень узла определяется следующим образом: - уровень корня дерева T равен нулю; - уровень корней поддеревьев любой вершины дерева на единицу больше, чем уровень этой вершины. Высота дерева – максимальное значение уровня какой-либо вершины дерева 8
Глубина узла v в дереве – длина пути из корня в v. Высота узла v в дереве – это длина самого длинного пути из v в какой-нибудь лист. Высота дерева – это высота его корня. Уровень узла равен разности высоты дерева и глубины узла. Упорядоченным называется дерево, в котором множество сыновей каждого узла упорядочено. При описании деревьев могут быть использованы термины из ботаники ( «корень» , «лист» , «ветвь» ), либо из генеалогии ( «отец» , 9
Лес — множество (обычно упорядоченное), не содержащее ни одного непересекающегося дерева или содержащее несколько непересекающихся деревьев. Ориентированное дерево — это ориентированный граф без циклов, в котором в каждую вершину, кроме одной, называемой корнем ориентированного дерева, входит одно ребро. В корень ориентированного дерева не входит ни одного ребра. Иногда, термин «ориентированное дерево» сокращают до «дерева» . 10
Дерево – это ориентированный граф без циклов, удовлетворяющий следующим условиям: Имеется в точности один узел, называемый корнем, в который не входит ни одно ребро; В каждый узел, кроме корня входит ровно одно ребро; Из корня к каждому узлу идет путь (единственный). 11
Существуют различные способы изображения деревьев: 12
Обходы деревьев Обход дерева – операция, связанная с посещением его вершин (под посещением понимается любая операция над вершиной дерева, не затрагивающая структуру дерева) При обходе каждая вершина должна быть посещена ровно один раз 13
Прямой обход дерева посетить корень обойти все поддеревья в направлении слева направо 1 2 3 6 4 5 7 8 12 9 10 11 14
Прямой обход (просмотр в глубину, просмотр сверху–вниз) определяется следующим рекурсивным алгоритмом: посетить корень обойти все поддеревья корня, начиная с самого левого 15
Обратный обход дерева обойти все поддеревья в направлении слева направо посетить корень 12 1 4 11 2 3 5 9 10 8 6 7 16
Обратный обход (просмотр снизу–вверх) дерева определяется следующим рекурсивным алгоритмом: обойти все поддеревья корня, начиная с самого левого посетить корень 17
Обход дерева по уровням посетить корень посетить вершины 1 -го, 2 -го и т. д. уровней в направлении слева направо 1 2 3 4 5 6 7 8 9 10 11 12 18
Обход деревьев по уровням : Вначале посещается корень дерева, затем – его сыновья, начиная с самого левого, затем – внуки. Так продолжается до тех пор, пока все вершины не посещены. 19
Рис. 8. Обходы деревьев 20
Представление деревьев Физическая реализация деревьев может быть выполнена различными способами. 1. Поскольку деревья являются частным случаем понятия графа, то для них можно применить любое представление, разработанное для графа общего вида (например, матрицу смежности или матрицу инцидентности). 21
22
23
24
2. Существуют представления, ориентированные на деревья. Наиболее простым и понятным из них является т. н. каноническое представление дерева, когда каждая вершина содержит ссылку на своего отца (корень, естественно, содержит пустую ссылку). Такое представление удобно, когда надо представить не одно дерево, а лес из нескольких деревьев. Но операций, которые удобно выполнять с помощью такого представления, не слишком много. Так, можно легко определить предков каждой вершины, но не ее потомков. Кроме того, модификация дерева затруднена при этом представлении. 25
3. Следующее представление дерева заключается в том, что каждая его вершина содержит список ссылок на сыновей этой вершины. Теперь можно легко выполнить поиск всех потомков конкретной вершины (но не ее предков!). 26
Часто два последних представления комбинируют, получая нечто вроде двунаправленного списка. Хотя полученная структура и является несколько избыточной, она позволяет легко проходить дерево в обоих направлениях: от листьев к корням и обратно. Рассмотрим конкретную реализацию этого представления на примере бинарных деревьев. 27
Двоичные деревья Двоичное (бинарное) дерево (ориентированное) — это ориентированное дерево, в котором исходящие степени вершин (число исходящих рёбер) не превосходят 2. На двоичном дереве основаны следующие структуры данных: двоичное дерево поиска двоичная куча красно-чёрное дерево АВЛ-дерево Фибоначчиева куча 28
Двоичное дерево поиска (бинарное поисковое дерево, БПД) – структура данных, предназначенная для выполнения следующих операций: поиска элемента по значению добавления нового элемента удаления элемента из дерева 29
Структура БПД Сыновья каждой вершины различаются: выделяются левый и правый сын Значения хранятся в каждой вершине дерева Для любого узла значения в левом поддереве меньше, а значения в правом поддереве – больше значения, хранящегося в корне 30
Бинарное поисковое дерево 31
Концевой обход бинарного дерева (симметричный или внутренний) Обойти левое поддерево Посетить корень Обойти правое поддерево 6 5 4 2 1 8 7 9 11 3 10 12 32
Механизм поиска в БПД Если дерево пусто, то поиск завершился неудачно. В противном случае сравниваем искомое значение со значением корня. Если эти значения равны, то искомое значение найдено; иначе рекурсивно выполняем эту же процедуру для левого или правого поддерева, в зависимости оттого, что больше – значение корня или искомое значение. 33
Поиск в БПД требует в лучшем случае О(log n) операций сравнения, где n – число элементов. Однако, если дерево не сбалансировано (т. е. длина одной из ветвей существенно больше длины другой), то эффективность поиска снижается и в худшем случае может достичь О(n) операций, когда дерево вырождается в единственную ветвь. 34
Поиск значения в БПД Пусть K – искомое значение, T – значение в корне дерева if (K==T) поиск завершен успешно else if (K<T) if (есть левый сын) выполнить поиск в левом поддереве else поиск завершен неудачно else if (есть правый сын) выполнить поиск в правом поддереве else поиск завершен неудачно 35
Примеры поиска в БПД Искомая величина – 18, поиск завершился неудачно 15 13 7 27 14 23 20 32 29 35 22 36
Примеры поиска в БПД Искомая величина – 20, поиск завершился успешно 15 13 7 27 14 23 20 32 29 35 22 37
Вставка новой вершины в БПД если БПД пусто, создаем единственную вершину и делаем ее корнем; иначе выполняем поиск вершины с добавляемым значением; если поиск успешен, вставка невозможна; в противном случае добавляем новую вершину и делаем ее сыном (левым или правым) той вершины, на которой остановились в процессе поиска 38
Пример создания БПД последовательностью вставок Добавляемые элементы: 7, 19, 14, 3, 5, 8, 22, 9, 1, 20, 2 7 39
Пример создания БПД последовательностью вставок Добавляемые элементы: 19, 14, 3, 5, 8, 22, 9, 1, 20, 2 7 19 40
Пример создания БПД последовательностью вставок Добавляемые элементы: 14, 3, 5, 8, 22, 9, 1, 20, 2 7 19 14 41
Пример создания БПД последовательностью вставок Добавляемые элементы: 3, 5, 8, 22, 9, 1, 20, 2 7 3 19 14 42
Пример создания БПД последовательностью вставок Добавляемые элементы: 5, 8, 22, 9, 1, 20, 2 7 3 19 5 14 43
Пример создания БПД последовательностью вставок Добавляемые элементы: 8, 22, 9, 1, 20, 2 7 3 19 5 14 8 44
Пример создания БПД последовательностью вставок Добавляемые элементы: 22, 9, 1, 20, 2 7 3 19 5 14 22 8 45
Пример создания БПД последовательностью вставок Добавляемые элементы: 9, 1, 20, 2 7 3 19 5 14 22 8 9 46
Пример создания БПД последовательностью вставок Добавляемые элементы: 1, 20, 2 7 3 1 19 5 14 22 8 9 47
Пример создания БПД последовательностью вставок Добавляемые элементы: 20, 2 7 3 1 19 5 14 22 8 20 9 48
Пример создания БПД последовательностью вставок Добавляемые элементы: 2 7 3 1 19 5 2 14 22 8 20 9 49
Проблемы балансировки 9 11 28 15 25 20 17 19 50
51
52
53
Физическая реализация БПД Наиболее удобной реализацией БПД представляется задание каждой его вершины в динамической памяти. В статическую область помещается лишь указатель на корень дерева: 54
struct Tree. Item{ int Info; Tree. Item* Father; Tree. Item* LSon; Tree. Item* RSon; Tree. Item(){LSon=RSon=NULL} }; Tree. Item* Root = NULL; // пустое дерево 55
bool find(int a, Tree. Item* &t) // поиск элемента { if (Root == NULL) { t = NULL; return false; } t = Root; for (; ; ) { if (t->Info == a) return true; if (t->Info > a) { if (t->LSon == NULL) return false; t = t->LSon; } else { if (t->RSon == NULL) return false; t = t->RSon; } } 56 }
bool Insert(int info) // добавление нового элемента в дерево { Tree. Item *s, *q; if (find(info, s)) return false; q = new Tree. Item; q->Info = info; if (s == NULL) { Root = q; q->Father = NULL; } else { q->Father = s; if (s->Info < info) s->RSon = q; else s->LSon = q; } return true; } STOP 57
58
Для уничтожения дерева концевой обход применить нельзя, т. к. посещение вершины приведет к ее удалению, и понятие «правое поддерево» станет неопределенным. Поэтому применяется обратный обход: 59
procedure Destroy(var T: TTree); {уничтожение дерева} procedure Round 1(var N: PTree. Node); begin if N=nil then exit; Round 1(N^. LSon); Round 1(N^. RSon); dispose(N); end; {Round 1} begin Round 1(T. Root); T. Root : = nil; end; 60
function Find(T: TTree; AInfo: TInfo; var N: PTree. Node): boolean; {при удачном поиске функция возвращает true, а параметр N содержит указатель на найденную вершину; при неудачном поиске функция возвращает false, а параметр N содержит указатель на вершину, на которой завершился поиск; при попытке поиска в пустом дереве параметр N содержит nil} var P: PTree. Node; 61
begin N : = nil; P : = T. Root; while true do begin if P=nil then begin Find : = false; exit; end; N : = P; if P^. Info = AInfo then begin Find : = true; exit; end; if P^. Info > AInfo then P : = P^. LSon else P : = P^. RSon; end; 62
Вставка и удаление вершин в БПД Очевидно, что вставляемая в БПД вершина будет являться листом и может быть добавлена только в одно конкретное место дерева (если мы, конечно, не желаем выполнить полное перестроение дерева). 63
Добавление новой вершины (со значением 10) к бинарному поисковому дереву 64
function Insert(var T: TTree; AInfo: TInfo): boolean; {вставка элемента по значению в бинарное поисковое дерево; функция возвращает false при обнаружении дубликата} var N, P: PTree. Node; 65
begin if Find(T, AInfo, N) then begin {нашли дубликат} Insert : = false; exit; end; Insert : = true; new(P); P^. Info : = AInfo; P^. RSon : = nil; P^. LSon : = nil; 66
if N=nil then begin{вставка первого эл-та в пустое дерево} T. Root : = P; P^. Father : = nil; end else begin P^. Father : = N; if N^. Info<AInfo then N^. RSon : = P else N^. LSon : = P; end; 67
Удаление вершины из БПД Выполняется немного сложнее и состоит из 2 -х этапов: · поиск вершины; · удаление. 68
Возможны три варианта в зависимости от того, сколько сыновей имеет удаляемая вершина (ни одного, двух): a)Вершина не имеет сыновей, т. е. является листом. Тогда просто удаляется ссылка на эту вершину; 69
а) исходное дерево; б) – дерево после удаления вершины 7 (листа); 70
в) дерево после удаления вершины 9, имеющей одного сына; 71
В случае (c) нужно найти такую вершину, чтобы ее удобно было переместить на место удаляемой. Чтобы найти такую вершину необходимо идти по дереву от исключаемого звена один раз налево и потом все время вправо (или наоборот), т. е. найти самую левую вершину в правом поддереве или самую правую вершину в левом поддереве, корнем которого является S. 72
Обозначим найденную вершину через T. Тогда для удаления вершины S необходимо: · перенести в нее содержимое информационной части вершины T; · удалить вершину T (поскольку она имеет не более одного сына, это действие особых проблем не вызывает). 73
11, имеющей двух сыновей 74
function Delete(var T: TTree; AInfo: TInfo): boolean; {удаление элемента по значению из бинарного поискового дерева; функция возвращает false при неудачном удалении} var N, P: PTree. Node; 75
procedure Delete. Node(P: PTree. Node); {удаление вершины, имеющей не более одного сына} var Q: PTree. Node; 76
begin if P^. LSon <> nil then Q : = P^. LSon else Q : = P^. RSon; if Q <> nil then Q^. Father : = P^. Father; if P^. Father = nil then T. Root : = Q else if (P^. Father)^. LSon = P then (P^. Father)^. LSon : = Q else (P^. Father)^. RSon : = Q; dispose(P); end; {Delete. Node} 77
begin if not Find(T, AInfo, N) then begin {не нашли удаляемый элемент} Delete : = false; exit; end; Delete : = true; if (N^. LSon<>nil)and(N^. RSon<>nil) then begin P : = N^. RSon; while P^. LSon <> nil do P : = P^. LSon; N^. Info : = P^. Info; Delete. Node(P); end else Delete. Node(N); end; 78
STOP 79
Лекция_24 Деревья.pptx