Алгоритм построения Эйлерова цикла — различия между версиями
(слово ширина) |
Lehanyich (обсуждение | вклад) (→Псевдокод) |
||
Строка 8: | Строка 8: | ||
'''Код проверки графа на эйлеровость:''' | '''Код проверки графа на эйлеровость:''' | ||
'''boolean''' checkForEulerPath(): | '''boolean''' checkForEulerPath(): | ||
− | '''int''' | + | '''int''' OddVertex <tex>= 0</tex> |
− | '''for''' <tex>v</tex> <tex>\in</tex> <tex>V</tex> | + | '''for''' <tex>v : v</tex> <tex>\in</tex> <tex>V</tex> |
− | '''if''' <tex>\operatorname{deg} v</tex> '''mod''' 2 == 1 | + | '''if''' <tex>\operatorname{deg}</tex>(<tex>v</tex>) '''mod''' <tex>2 == 1</tex> |
− | + | OddVertex++ | |
− | '''if''' | + | '''if''' OddVertex <tex> > 2 </tex><font color=darkgreen>// если количество вершин с нечетной степенью больше двух, то граф не является эйлеровым</font> |
'''return''' ''false'' | '''return''' ''false'' | ||
− | '''boolean''' | + | '''boolean''' visited(<tex>|V|</tex>, ''false'') <font color=darkgreen>// массив инициализируется значениями ''false''</font> |
− | '''for''' <tex>v</tex> <tex>\in</tex> <tex>V</tex> | + | '''for''' <tex>v : v</tex> <tex>\in</tex> <tex>V</tex> |
− | '''if''' <tex>\operatorname{deg} v</tex> > 0 | + | '''if''' <tex>\operatorname{deg}</tex>(<tex>v</tex>) <tex> > 0</tex> |
− | dfs(<tex>v</tex>, | + | dfs(<tex>v</tex>, visited) |
− | break | + | '''break''' |
− | '''for''' <tex>v</tex> <tex>\in</tex> <tex>V</tex> | + | '''for''' <tex>v : v</tex> <tex>\in</tex> <tex>V</tex> |
− | '''if''' <tex>\operatorname{deg} v</tex> > 0 '''and''' '''not''' | + | '''if''' <tex>\operatorname{deg}</tex>(<tex>v</tex>) <tex> > 0</tex> '''and''' '''not''' visited[<tex>v</tex>] <font color=darkgreen>// если количество компонент связности, содержащие ребра, больше одной,</font> |
'''return''' ''false'' <font color=darkgreen> // то граф не является эйлеровым</font> | '''return''' ''false'' <font color=darkgreen> // то граф не является эйлеровым</font> | ||
'''return''' ''true'' <font color=darkgreen>// граф является эйлеровым</font> | '''return''' ''true'' <font color=darkgreen>// граф является эйлеровым</font> | ||
'''Код построения эйлерова пути:''' | '''Код построения эйлерова пути:''' | ||
− | '''function''' findEulerPath(<tex>v</tex> | + | '''function''' findEulerPath(<tex>v</tex>): <font color=darkgreen> // если граф является полуэйлеровым, то алгоритм следует запускать из вершины нечетной степени </font> |
− | Stack S | + | '''for''' <tex>u : u \in V</tex> |
− | S.push(<tex>v</tex>) | + | '''if''' <tex>\operatorname{deg}</tex>(<tex>u</tex>) '''mod''' <tex>2 == 1</tex> |
− | '''while not''' S. | + | <tex>v = u</tex> |
− | <tex>w</tex> | + | '''break''' |
− | '''if''' <tex> | + | Stack <tex>S</tex> |
− | + | <tex>S</tex>.push(<tex>v</tex>) | |
− | + | '''while not''' <tex>S</tex>.empty() | |
− | ''' | + | <tex>w = </tex> <tex>S</tex>.top() |
− | S.pop() | + | '''for''' <tex>u : u \in V</tex> |
+ | '''if''' (<tex>w, u</tex>) <tex>\in E</tex> <font color=darkgreen> // нашли ребро, по которому ещё не прошли</font> | ||
+ | <tex>S</tex>.push(<tex>u</tex>) <font color=darkgreen> // добавили новую вершину в стек</font> | ||
+ | <tex>E</tex>.remove(<tex>w, u</tex>) | ||
+ | '''break''' | ||
+ | '''if''' <tex> w == S</tex>.top() | ||
+ | <tex>S</tex>.pop() <font color=darkgreen> // не нашлось инцидентных вершине <tex>w</tex> рёбер, по которым ещё не прошли</font> | ||
print(<tex>w</tex>) | print(<tex>w</tex>) | ||
</font> | </font> |
Версия 10:35, 6 декабря 2015
Содержание
Алгоритм
Описание алгоритма
Алгоритм находит Эйлеров цикл как в ориентированном, так и в неориентированном графе. Перед запуском алгоритма необходимо проверить граф на эйлеровость. Чтобы построить Эйлеров путь, нужно запустить алгоритм из вершины с нечетной степенью.
Алгоритм напоминает поиск в ширину. Главное отличие состоит в том, что пройденными помечаются не вершины, а ребра графа. Начиная со стартовой вершины строим путь, добавляя на каждом шаге не пройденное еще ребро, смежное с текущей вершиной. Вершины пути накапливаются в стеке . Когда наступает такой момент, что для текущей вершины все инцидентные ей ребра уже пройдены, записываем вершины из в ответ, пока не встретим вершину, которой инцидентны не пройденные еще ребра. Далее продолжаем обход по не посещенным ребрам.
Псевдокод
Код проверки графа на эйлеровость:
boolean checkForEulerPath(): int OddVertexfor if ( ) mod OddVertex++ if OddVertex // если количество вершин с нечетной степенью больше двух, то граф не является эйлеровым return false boolean visited( , false) // массив инициализируется значениями false for if ( ) dfs( , visited) break for if ( ) and not visited[ ] // если количество компонент связности, содержащие ребра, больше одной, return false // то граф не является эйлеровым return true // граф является эйлеровым
Код построения эйлерова пути:
function findEulerPath(): // если граф является полуэйлеровым, то алгоритм следует запускать из вершины нечетной степени for if ( ) mod break Stack .push( ) while not .empty() .top() for if ( ) // нашли ребро, по которому ещё не прошли .push( ) // добавили новую вершину в стек .remove( ) break if .top() .pop() // не нашлось инцидентных вершине рёбер, по которым ещё не прошли print( )
Доказательство корректности
Теорема: |
Данный алгоритм находит корректный эйлеров путь. |
Доказательство: |
TODO: Довести до ума
|
Рекурсивная реализация
function findEulerPath(: Vertex): for remove findEulerPath( ) print( )
Время работы
Если реализовать поиск ребер инцидентных вершине и удаление ребер за
Чтобы реализовать поиск за , для хранения графа следует использовать списки смежных вершин; для удаления достаточно добавить всем ребрам свойство бинарного типа.