рефераты конспекты курсовые дипломные лекции шпоры

Реферат Курсовая Конспект

Файл listgraph.cpp

Файл listgraph.cpp - раздел Образование, Основные операции при работе с деревьями // Собственно Алгоритм Крускала Double Listgraph::minskeleton( ...

// Собственно алгоритм Крускала

double ListGraph::minSkeleton(

// Выходной поток для вывода результирующей информации:

std::ostream & out,

// Нагрузка на ребра графа:

const GraphWeight & gw) {

// Суммарный вес найденного минимального остовного дерева:

double weight = 0;

// Пирамида, содержащая информацию о ребрах графа:

ArrayHeap<Arc> arcs(vertexNumber * vertexNumber / 2);

 

// Структура узла в лесе, представляющем частично построенное

// минимальное остовное дерево

struct SkeletonNode {

int node; // номер узла исходного графа

int next; // ссылка на родительский узел

// Конструкторы:

SkeletonNode(int n = 0) : node(n), next(-l) {}

SkeletonNode(const SkeletonNode & node) : node(node.node), next(node.next) {}

};

// Начальное заполнение пирамиды ребер:

// просматриваются все ребра графа,

//и информация о них заносится в пирамиду,

for (int i = 0; i < vertexNumber; i++) {

Iterator<int> *neighbors = graph[i].iterator();

while (neighbors->hasMoreElements()) {

int j = **neighbors;

}

// Граф неориентированный, поэтому для исключения дублирования

// информации рассматриваются только дуги, ведущие из вершины

// с меньшим номером в вершину с большим номером. Петли

// (если они есть) сразу же исключаются,

if (i < j) {

// Добавление ребра в пирамиду:

arcs += Arc(i, j, gw.arcLength(i, j));

}

++*neighbors;

}

delete neighbors;

// Начальное заполнение леса: каждая вершина графа представляет

// собой отдельное дерево, состоящее из единственной вершины.

SkeletonNode skeleton[vertexNumber];

for (int i = 0; i < vertexNumber; i++) {

skeleton[i] = SkeletonNode(i);

}

// Основной цикл по ребрам, включенным в пирамиду

while (!arcs.empty()) {

// Очередное ребро берется с вершины пирамида и исключается из нее

Arc nextArc = *arcs;

arcs, remove ();

// u и v - концы выбранного ребра

int u = nextArc. from, v = nextArc.to;

// Следующие два цикла находят корни деревьев,

// содержащих эти вершины:

while(skeleton[u].next ! = -1) u = skeleton[u].next;

while(skeleton[v].next != -1) v = skeleton[v].next;

if (u != v) {

// Ребро включается в остовное дерево,...

out « nextArc « "; ";

weight += nextArc.weight;

// ... а два дерева соединяются в одно.

skeleton[u]-next = v;

}

return weight;

}

 

При попытке вычислить минимальное остовное дерево для графа, приведенное на рис. 9, с помощью вызова метода:

cout « testGraph.minSkeleton(cout, arcsWeight);

В стандартный выходной поток будет выведена следующая информация:

(2,5); (0,3); (5,8); (0,6); (0,1); (1,4); (4,7); 15

Что и свидетельствует о том, что минимальное остовное дерево построено правильно, поскольку содержит ребра (2, 5), (0, 3), (5, 8), (0, б), (0, 1), (1, 4), (4, 7) и суммарный вес всех ребер составляет минимально возможную величину 15.

Еще один алгоритм построения минимального остовного дерева напоминает алгоритм Дейкстры для поиска наименьшего пути между двумя вершинами в графе и носит название алгоритма Прима (R. С. Prim).

В этом алгоритме построение остовного дерева начинается с одной вершины, к которой затем добавляются ребра таким образом, чтобы каждое новое ребро одним своим концом опиралось в уже построенную часть дерева, а другой конец лежал бы в множестве еще не присоединенных к дереву вершин. Из всех таких ребер на каждом шаге выбирается ребро с наименьшим весом. Для того чтобы выбор ребра был бы наиболее эффективен, так же, как и в алгоритме Дейкстры, в алгоритме Прима используется промежуточная структура данных — массив, элементы которого содержат информацию о расстоянии от каждой из вершин до уже построенной части остовного дерева. Таким образом, с помощью однократного просмотра такого массива всегда можно выбрать ребро минимальной длины.

Будем считать, что вершины, не соединенные ребрами с уже построенной частью остовного дерева, находятся от этой части на бесконечно большом расстоянии. После того как очередная вершина будет выбрана и присоединена к остовному дереву, все инцидентные ей ребра просматриваются, чтобы скорректировать информацию о расстояниях. Эта часть алгоритма также очень похожа на соответствующую коррекцию массива расстоянии из алгоритма Дейкстры. Если оказывается, что очередная выбранная вершина находится на бесконечно большом расстоянии от уже построенной части дерева, то это означает, что завершено построение дерева для одной компоненты связности графа и, значит, одного остовного дерева для графа построить невозможно (в этом последнем случае стоит говорить об остовном лесе).

Если для графа, изображенного на рис. 9, начать поиск минимального остовного дерева с вершины 0, то к дереву будут последовательно присоединяться ребра 0—3 (длиной 1), 0—1 (2), 0—6 (2), 1—4 (3), 4—7 (4), вершина 2 (+∞), 2—5(1), 2—8 (2).

На рис. 11 показана последовательность построения минимального остовного дерева для графа, изображенного на рис. 9.

Реализация алгоритма Прима показана в листинге в виде определения метода minSkeletonPrim, который так же, как и метод minSkeleton, в качестве аргумента получает выходной поток для печати информации о найденных ребрах минимального остовного дерева, а в качестве результата выдает суммарный вес полученного остовного дерева.

 

Листинг : Алгоритм Прима нахождения минимального остовного дерева

 

double ListGraph::minSkeletonPrim(

// Выходной поток для вывода результирующей информации:

std::ostream & out,

// Нагрузка на ребра графа:

const GraphWeight & gw) {

// Множество непройденных вершин (сначала - все вершины)

Set notPassed(0, vertexNumber-1);

notPassed.addScale(0, vertexNumber-1);

// Массив расстояний от вершин до уже построенной части

double *dist - new double[vertexNumber];

// Массив направлений от новых вершин к уже построенной части

double *ends = new double[vertexNumber];

// Инициализация массивов расстояний и направлений

for (int i = 0; i < vertexNumber; i++) {

dist[i] = INFINITY;

ends[i] = -1;

}

// Суммарный вес построенной части дерева

double sumWeight =0;

// Основной цикл поиска новых вершин

while (!notPassed.empty()) {

// Поиск ближайшей вершины

double minDist = INFINITY;

Iterator<int> *iVertices = notPassed.iterator();

int minVertex = **iVertices;

while (iVertices->hasMoreElements()) {

int nextVertex = **iVertices;

if (dist[nextVertex] < minDist) {

minDist = dist[nextVertex];

minVertex = nextVertex;

} ++*iVertices; }

delete iVertices;

if (dist[minVertex] < INFINITY) {

// Присоединяем очередное ребро

out << "(" << ends[minVertex] << "," << minVertex <<”);”;

sumWeight += minDist;

}

notPassed -= minVertex;

// Новая вершина присоединена;

// корректируем информацию о расстояниях

Iterator<int> *neighbors = graph[minVertex].iterator();

while (neighbors->hasMoreElements()) {

int next = **neighbors;

if (notPassed.has(next)&& gw.arcLength(minVertex, next) < dist[next]) {

dist[next] = gw.arcLength(minVertex, next);

ends[next] = minVertex;

} ++*neighbors;

} delete neighbors;

} return sumWeight;

}

 

Рис. 11. Этапы построения остовного дерева согласно алгоритму Прима

Если применить метод minSkeietonPrim к графу, изображенному на рис. 9

cout « testGraph.minSkeleton(cout, arcsWeight);

то, разумеется, результат будет примерно тем же самым, что и при применении метода minskeieton, реализующего жадный алгоритм:

(0,3); (0,1); (0,6); (1,4); (4,7); (2,5); (2,8); 15

Алгоритмы имеют разную производительность на различных графах. Скорость работы алгоритма Крускала зависит, прежде всего, от количества ребер в графе и слабо зависит от количества вершин. Напротив, скорость работы алгоритма Прима определяется количеством вершин и слабо зависит от числа ребер. Следовательно, алгоритм Крускала следует применять в случае неплотных или разреженных графов, у которых количество ребер мало по сравнению с количеством ребер у полного графа. Если известно, что ребер в графе достаточно много, то для поиска минимального остовного дерева лучше применять алгоритм Прима.

 

– Конец работы –

Эта тема принадлежит разделу:

Основные операции при работе с деревьями

Основные операции при работе с деревьями... Определение глубины дерева... Обход дерева на заданную глубину включение нового значения в дерево...

Если Вам нужно дополнительный материал на эту тему, или Вы не нашли то, что искали, рекомендуем воспользоваться поиском по нашей базе работ: Файл listgraph.cpp

Что будем делать с полученным материалом:

Если этот материал оказался полезным ля Вас, Вы можете сохранить его на свою страничку в социальных сетях:

Все темы данного раздела:

Оптимизация поиска в дереве
  Основное свойство дерева соответствует пословице " дальше в лес - больше дров" . Точнее, количество просматриваемых вершин от уровня к уровню растет в геометрической прогр

Нумерация вершин
  Способы обхода дерева.В деревьях обход вершин возможен только с использованием рекурсии, поэтому и их логическая нумерация производится согласно последовательности их рекурсивного о

Поиск и включение в двоичное дерево
Свойства двоичного дерева позволяют применить в нем алгоритм поиска, аналогичный двоичному поиску в массиве. Каждое сравнение искомого значения и значения в вершине позволяет выбрать для следующего ша

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

Преобразование лозы в сбалансированное двоичное дерево.
  Этот этап алгоритма более содержательный и поэтому менее очевидный. Поэтому сначала будет разобран простой пример, а потом будет дано его обобщение. Пусть есть лоза, котора

Алгоритмы представления графа
  При программировании задач обработки сетевых структур требуется решить вопрос о представлении графа структурами данных языка программирования. Выбор представления графа определяется

Файл setgraph.h
#include "graph.h" #include "set.h" // Определение класса для работы с множествами class SetGraph : public Graph { Set **graph; // Массив множеств дуг

Представление графа в виде матрицы смежности
  Еще один распространенный способ представления графа — это представление в виде матрицы смежности размером N * N (рис.1). B этой матрице в элементе с индексами (i,j) записывается ин

Файл MatrixGraph.cpp
#include "MatrixGraph.h"   // Реализация конструктора - заказ и инициализация памяти // под двумерный массив логических значений MatrixGraph::Matr

Представление графа в виде связанного списка
Списки вообще удобны тем, что могут содержать переменное количество элементов, при этом общий размер занимаемой ими памяти соответствует количеству элементов списка. Каждый элемент списка будет сод

Файл ListGraph.h
#include "graph.h" // Описание родительского класса   // Описание шаблона классов для представления // простых однонаправленных списков template &

Файл ListGraph.cpp
#include "ListGraph.h"   // Реализация операций над списком. // Добавление нового элемента в список template <class T> void List<

Представление графа в виде списка дуг
  Иногда используются и другие представления графов, например, для случая очень разреженных графов, когда при большом количестве N вершин графа число дуг существенно меньше NXN, напри

Файл ArcGraph.h
#include "graph.h" // Определение родительского класса // Описание класса для представления A-графа class ArcGraph : public Graph { // Дуга представлена элемент

Файл ArcGraph.cpp
«include "ArcGraph.h"   //Реализация операции добавления дуги void ArcGraph::addArc(int from, int to) { // Сначала проверяем правильность задания

Файл convert.срр
#include "SetGraph.h" #include "MatrixGraph.h" #include "ListGraph.h" #include "ArcGraph.h"   // Функция пр

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

Определение путей и контуров Эйлера
  Путь Эйлера проходит по каждому ребру в графе только один раз. Контур Эйлера проходит каждое ребро в графе тоже один раз, а также начинается и заканчивается в одной и той же вершине

Поиск кратчайших путей
Путем в графе называют чередующуюся последовательность вершин и дуг v1, e1, v2, e2,... vn-1 en-1, vn, в которой каждый элемент vi— вершина графа, а каждый элемент еi — дуга графа, ведущая из пре

Алгоритм Э. Дейкстры.
Опишем алгоритм нахождения такого пути при условии, что длины всех дуг неотрицательны. Этот алгоритм был предложен и опубликован Э. Дейкстрой (Е. W. Dijkstra), поэтому и носит его имя. Алг

Алгоритм Флойда — Уоршалла
Идея алгоритмом Флойда — Уоршалла, состоит в следующем. Будем рассматривать последовательность матриц смежности. В этой матрице элемент с индексами (i,j) равен +∞, если в графе нет ребра, вед

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

Файл listgraph.h
// Класс ListGraph задает структуру L-графа class ListGraph {   // Массив списков дуг List<int> *graph; // Количество вершин графа i

Файл Arc.h
// Структура ребра для алгоритма Крускала: сравнение ребер // происходит по их весам   struct Arc { int from, to; double weight; Arc(int f

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

Сортировка вставками
  Метод сортировки заключается в том, что отдельно анализируется каждый конкретный элемент, который затем помещается в надлежащее место среди других, уже отсортированных элементов. Сл

Пузырьковая сортировка
  Метод сортировки, который многие обычно осваивают раньше других из-за его исключительной простоты, называется пузырьковой сортировкой (bubble sort), в рамках которой выполняются сле

Быстрая сортировка
  Алгоритм быстрой сортировки обладает привлекательными особенностями: он принадлежит к категории обменных (in-place) сортировок (т.е., требует всего лишь небольшого вспомогательного

Сортировка слиянием
  Рассматривается сортировка слиянием (mergesort), которая является дополнением быстрой сортировки в том, что она состоит из двух рекурсивных вызовов с последующей процедурой слияния.

Пирамидальная сортировка
  Итак, мы постепенно переходим от более-менее простых к сложным, но эффективным методам. В качестве некоторой прелюдии к основному методу, рассмотрим перевернутую сортировку

Двоичный поиск
Если данные отсортированы, то может использоваться очень хороший метод поиска, названный двоичным поиском. При таком поиске используется метод "разделяй и властвуй". Сначала производится

Работа со словарем. Иоиск и вставка. Хеширование.
  Довольно часто встречаются ситуации, когда обработке подлежат много маленьких строк — слов, которые надо сохранять в некоторой единой структуре — словаре. Сами слова н

Файл dictionary.h
// Класс, представляющий словарь в виде хеш-таблицы classHashDictionary { private: static const intP = 557;

Файл dictionary.cpp
// Реализация функций intHashDictionary::code(char c) { returnstrchr("abcdefghijklmnopqrstuvwxyz&

Файл "hashtable.h".
  // Класс, представляющий хеш-таблицу пар (ключ, значение), причем // ключом является строка, а значением может быть произвольный объект. //В таблице хранятся не са

Алгоритм прямого поиска подстроки в строке
  1. Установить i на начало строки S, т.е. i = 0. 2. Проверить, не вышло ли i + M за границу N строки S. Если да, то алгоритм

Хотите получать на электронную почту самые свежие новости?
Education Insider Sample
Подпишитесь на Нашу рассылку
Наша политика приватности обеспечивает 100% безопасность и анонимность Ваших E-Mail
Реклама
Соответствующий теме материал
  • Похожее
  • Популярное
  • Облако тегов
  • Здесь
  • Временно
  • Пусто
Теги