- •Структуры и алгоритмы обработки данных
- •Алгоритмы. Основные определения
- •От задачи к программе
- •Написание программы.
- •Типы данных, структуры данных и абстрактные типы данных
- •Указатели и курсоры
- •Время выполнения программ
- •Измерение времени выполнения программы
- •Степень (порядок) роста
- •Вычисление времени выполнения программ
- •Линейные абстрактные типы данных атд «Список»
- •Реализация списков посредством массивов
- •Реализация списков с помощью указателей
- •Атд «Стек»
- •Атд «Очередь»
- •Реализация очередей с помощью циклических массивов
- •Нелинейные абстрактные типы данных Деревья
- •Порядок узлов
- •Прямой, обратный и симметричный обходы дерева
- •Помеченные деревья и деревья выражений
- •Представление деревьев с помощью массивов
- •Специальные виды множеств атд “Дерево двоичного поиска”
- •Атд "Словарь", основанный
- •Представление ориентированных графов
- •Атд для ориентированных графов
- •Задача нахождения кратчайшего пути
- •Int **c, // массив стоимостей
- •Int *d) // массив кратчайших
- •Остовные деревья минимальной стоимости
- •Обход графов
- •Поиск в ширину
- •Поиск в глубину
- •Сортировка
- •Простые схемы сортировки Метод «пузырька»
- •Сортировка вставками
- •Быстрая сортировка
- •Пирамидальная сортировка
- •«Карманная» сортировка
- •Порядковые статистики
- •Методы разработки алгоритмов. Типы алгоритмов
- •Алгоритмы «разделяй и властвуй» (метод декомпозиции)
- •Баланс подзадач
- •Динамическое программирование
- •Перемножение нескольких матриц
- •Шаг 1: строение оптимальной расстановки скобок
- •Шаг 2: рекуррентное соотношение
- •Шаг 3: вычисление оптимальной стоимости
- •Void MatrixChainOrder(int n, // кол-во матриц
- •Int p[], // размеры матриц
- •Int **s) // оптимальное k
- •Шаг 4: построение оптимального решения
- •Int **s, // таблица, полученная
- •Int I, // индексы
- •Когда применимо динамическое программирование?
- •Оптимальность для подзадач
- •Перекрывающиеся подзадачи
- •«Жадные» алгоритмы
- •"Жадные" алгоритмы как эвристики
- •Когда применим жадный алгоритм?
- •Принцип жадного выбора
- •Оптимальность для подзадач
- •Поиск с возвратом
- •Функции выигрыша
- •Метод ветвей и границ
- •Структуры данных и алгоритмы для внешней памяти
- •Внешняя сортировка
- •Хранение данных в файлах
- •Простая организация данных
- •Хешированные файлы
- •Индексированные файлы
- •Содержание
- •Глава I. Линейные абстрактные типы данных 31
- •Глава II. Сортировка 108
-
Обход графов
При решении задач, связанных с графами, необходим эффективный метод систематического обхода вершин и дуг графов. Существует два наиболее часто используемых метода обхода графов: поиск в глубину и поиск в ширину.
Поиск в ширину
- один из базисных алгоритмов, составляющий основу многих других. Например, алгоритм Дейкстры и алгоритм Прима можно считать обобщением поиска в ширину.
Пусть задан граф G=(V,E) и фиксирована начальная вершина s. Алгоритм поиска в ширину перечисляет все достижимые из s вершины в порядке возрастания расстояния от s. Расстоянием считается длина кратчайшего пути. В процессе поиска из графа выделяется часть, называемая «деревом поиска в ширину», с корнем s. Именно она содержит все достижимые из s вершины и только их. Для каждой из них путь из корня в дереве поиска будет одним из кратчайших путей из начальной вершины в графе. Алгоритм применим и к ориентированным, и к неориентированным графам.
Название объясняется тем, что в процессе поиска мы идем вширь, т.е. сначала просматриваем все соседние вершины, затем соседей соседей и т.д.
Для наглядности будем считать, что в процессе работы алгоритма вершины графа могут быть белыми, серыми и черными. Вначале они все белые, затем в ходе работы алгоритма белая вершина может серой, а серая – черной.
Если вершина имеет серый или черный цвет, то она уже посещалась алгоритмом. Различие между серыми и черными вершинами используется для управления порядком обхода: серые вершины образуют «линию фронта», а черные – «тыл». Т.е. поддерживается такое свойство: если u черная вершина, то она может соединяться ребром только с черной или серой вершиной. Только серая вершина может иметь смежные белые (непосещенные) вершины.
Вначале работы алгоритма дерево поиска состоит только из корня – начальной вершины s, u=s. Как только алгоритм обнаруживает новую белую вершину v, смежную с ранее найденной вершиной u, вершина v вместе с ребром u->v добавляется к дереву поиска, становясь сыном вершины u, а u становится родителем v. Каждая вершина обнаруживается лишь однажды, так что двух родителей у нее быть не может.
Обычно процедуру, реализующую этот алгоритм, называют BFS(), что является сокращением от breadth-first search – поиск в ширину.
Для каждой вершины графа будем дополнительно хранить цвет и ее предшественника в массивах color[] и pi[]. Если предшественника нет или он еще не обнаружен, то pi[]=NULL.
Кроме того расстояние от s до u записывается в массив d[u]. Также будем использовать очередь Q для хранения серых вершин.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
BFS(GRAPH G, vertex s) { QUEUE Q; /* очередь для вершин */ Vertex u, v; For (для каждой вершины u графа G, кроме s ) { color[u]=WHITE; /*вершины становятся белыми */ pi[u]=NULL; /* родителем всех вершин считается NULL */ d[u]=MAXDISTANCE; /* все расстояния максимально возможные */ } /* for */ color[s]=GRAY; d[s]=0; pi[s]=NULL; ENQUEUE(s,Q); /* поместить s в очередь Q */ While(EMPTY(Q)) /* пока очередь не пустая */ { u=FRONT(Q); /* извлекаем первый элемент из очереди */ for(для всех вершин v смежных с u) if (color[v]==WHITE) { color[v]=GRAY; d[v]=d[u]+1; pi[v]=u; ENQUEUE(v,Q); /* поместить v в очередь Q */ } /*if*/ DEQUEUE(Q); /* удаляем элемент из очереди / color[u]=BLACK; } } |
Основной цикл программы (строки 16-29) выполняется пока очередь не пуста, т.е. существуют серые вершины (вершины, которые уже обнаружены, но списки смежности которых еще не просмотрены). В строке 18 первая такая вершина помещается в u. Цикл 19-26 просматривает все смежные с ней вершины. Обнаружив среди них белую вершину, мы делаем ее серой (строка 22) объявляем u ее родителем (строка 24) и устанавливаем расстояние на 1 больше чем у родителя (строка 23). Эта вершина добавляется в хвост очереди Q (строка 25). После этого можно удалить u из очереди (строка 27), перекрасив эту вершину в черный цвет (строка 28).
Т.О., в результате работы программы получим два массива pi[] с родителем для каждой вершины и d[] с кратчайшим расстоянием до s.