Графовые нейронные сети — новая и перспективная область развития нейронных сетей, которая нашла применение в анализе различных структур данных, например, в социальной сфере.
Поиск, обход в глубину и ширину в графе: алгоритм, описание
Поиск в ширину и поиск в глубину — все эти задачи относятся к категории «обход графа» и решаются, когда необходимо выполнить операции над вершинами графа.
Граф — это множество вершин одного типа, соединенных ребрами. Каждое отдельное ребро соединяет только две вершины; очень редко ребро может соединять вершину с самой собой.
- неориентированные — в этих графах важно только присутствие связи между вершинами;
- ориентированные — в этих графах важны присутствие и направление связей между вершинами;
- взвешенные — в этих графах важны присутствие, направление и вес связей между вершинами.
Восстановление ширины и глубины или обход графа может быть выполнен для всех типов графов. Обход — это просто переход от вершины к вершине для определения свойств связей между этими вершинами.
Задачи для обхода графа вширь или вглубь могут быть следующими:
- поиск кратчайшего пути между какими-то вершинами;
- найти в графе «дерево» с наименьшим суммарным весом ребер;
- раскрасить вершины графа разными цветами, чтобы у смежных вершин не было одинакового цвета;
- поиск пути, проходящего кратчайшим путем по всем вершинам графа;
- и др.
Поиск в ширину
Breadth First Search (BSD) сначала рассматривает все вершины, смежные с исходной вершиной, а затем переходит к их потомкам. Он характеризуется беспрепятственным движением «от соседа к соседу», где один шаг — это посещение «соседа». При его выполнении формируется очередь узлов, которые еще не были пройдены. Этот алгоритм выполняется до тех пор, пока не будет найдено искомое значение.
Поиск диапазона выполняется в следующей последовательности действий:
- Необходимо определить стартовую вершину, с которой начинать алгоритм поиска в ширину.
- Обрабатывается стартовая вершина, а после ее обработки она включается в список «посещенных вершин».
- Образуется очередь их ближайших соседей к стартовой вершине, которые будут посещены в ближайшее время.
- Организовывается непрерывный цикл, по исключению и включению в очередь пройденных и непройденных вершин.
Поиск в глубину
Поиск в глубину или DFS (Depth First Search) дает представление о таком поиске, где мы указываем начальный узел и направление движения. Поиск следует в этом направлении до конца пути или пока не будет найдено желаемое пиковое значение. Если в конце пути значение не найдено, поиск возвращается «назад» к ближайшей точке отклонения и выбирается новое направление для пути глубины.
Глубинный поиск характеризуется двумя особенностями:
- стек — это структура для запоминания вершин, которые еще не были обработанными;
- список — это структура для запоминания уже посещенных вершин.
При поиске в глубину выполняется следующая последовательность действий:
- Задается стартовая вершина.
- Определяется искомое значение.
- Задается вероятный путь для поиска нужного значения.
- Если в процессе прохождения пути цель была достигнута, то поиск в глубину считается завершенным. Если же нет, то поиск происходит по новому пути, при этом новый путь выбирается с учетом уже посещенных вершин.
Алгоритм поиска в глубину характеризуется движением к концу пути.
Пример BFS
Давайте рассмотрим пример работы алгоритма поиска по глубине. Мы используем неориентированный граф с 5 вершинами.
Мы начинаем с вершины 0. Алгоритм BFS начинает с добавления ее в список посещенных вершин и размещения всех соседних вершин в стеке.
Затем мы посещаем элемент, находящийся в верхней части очереди, т.е. 1, и переходим к соседним вершинам. Поскольку 0 уже был посещен, мы посещаем 2.
Узел 2 имеет соседний непосещенный узел 4, поэтому мы добавляем его в конец очереди и посещаем узел 3, который находится в начале очереди.
В очереди остается только 4, потому что единственный соседний узел с 3, 0, уже был посещен. Мы посещаем узел 4.
Поскольку конец пуст, мы завершили обход по всей ширине графа.
BFS в C
#include #define SIZE 40 struct queuestruct queue* createQueue(); void enqueue(struct queue* q, int); int dequeue(struct queue* q); void display(struct queue* q); int isEmpty(struct queue* q); void printQueue(struct queue* q); struct node struct node* createNode(int); struct Graph struct Graph* createGraph(int vertices); void addEdge(struct Graph* graph, int src, int dest); void printGraph(struct Graph* graph); void bfs(struct Graph* graph, int startVertex); int main() void bfs(struct Graph* graph, int startVertex) enqueue(q, startVertex) = 1; while(!isEmpty(q)) adjListscurrentVertex; while(temp) vertex; if(graph->(temp); while(temp == 0) visitedadjVertex = 1; enqueue(q, adjVertex);>temp = temp->next;>>>struct node* createNode(int v) vertex = v; newNode->next = NULL; return newNode;>struct Graph* createGraph(int vertices) numVertices = vertices; graph->adjLists = malloc(vertices * sizeof(struct node*)); graph->visited = malloc(vertices * sizeof(int)); int i; for (i = 0; i adjListsi = NULL; graph->visitedi = 0;>return graph;>void addEdge(struct Graph* graph, int src, int dest)/>next = graph->adjListssrc; graph->adjListssrc = newNode; // Add edge from dest to src newNode = createNode(src); newNode->next = graph->adjListsdest; graph->adjListsdest = newNode;>struct queue* createQueue() front = -1; q->rear = -1; return q;>int isEmpty(struct queue* q) rear == -1) return 1; else return 0;>void enqueue(struct queue* q, int value) rear == SIZE-1) printf(" front == -1) q->front = 0; q->rear++; q->itemsq->rear = value;>>Queue is Full!!!"); else int dequeue(struct queue* q) - itemsq->front; q->front++; if(q->front>q->иначе
front = q->rear = -1;>>return item;>назад) void printQueue(struct queue *q) front; if(isEmpty(q)) else фронт; i itemsi);>>> back + 1; i++)
#include #include using namespace std; class Graph ; Graph::Graph(int vertices) void Graph::addEdge(int src, int dest) BFS Java код (Java code) void Graph::BFS(int startVertex)>>>import java.io.*; import java.util.*; class Graph > public static void main(String args)import collections def bfs(graph, root): visited, queue = set(), collections.deque(root) visited.add(root) while queue: vertex = queue.popleft() for neighbour in graphvertex: if neighbour not in visited: visited.add(neighbour) queue.append(neighbour) if __name__ == '__main__': graph = breadth_first_search(graph, 0)
Рекомендуемый хостинг TIMEWEB
Стабильный хостинг, на котором размещена социальная сеть EVILEG. Для проектов Django мы рекомендуем VDS-хостинг.
- Алгоритм Прима
- Алгоритм Краскала
- Алгоритм DFS («Depth-first search» или «Поиск в глубину»)
- Граф. Структура данных.
- Двоичное дерево поиска (Binary Search Tree (BST))
- Обход дерева – центрированный (inorder), прямой (preorder) и обратный (postorder) (три основных способа обхода)
Рекомендуемые статьи по этой теме
Псевдокод
В этой статье было 0 вопросов
Обход в ширину (breadth-first search, BFS)
Вопрос. Все, что мы видели раньше, только в коде. G.Adj - список смежности данного графа. Для каждой вершины, которая еще не была посещена, мы окрашиваем ее в серый цвет, указывая, что ее поле истинно; таким образом мы проходим через все вершины. Почему мы вызываем dfs для каждой вершины в init()? Мы не можем начать с первой вершины, потому что в приведенном выше графе dfs немедленно закончится, если мы начнем с вершины 3, поскольку из нее нет исходящих дуг.
Он систематически обходит все узлы графа. В чем разница с обходом по глубине? Обход в глубину "прыгает" между строками списка смежности по одному узлу за раз, в то время как обход в ширину обходит все возможные узлы сразу, как это работает в примере:
Сначала обходятся все узлы, соседние с исходным узлом, затем все узлы, соседние с исходным узлом, и так далее. Вот еще один пример, который, на мой взгляд, более наглядно демонстрирует разницу между обходами в глубину и ширину: В первом примере граф обходится достаточно равномерно.
Упорядочивание BFS
Псевдокод с краткими пояснениями:
Пусть G = (V, E) будет графиком с n вершин. Напомним, что N (v) - это набор соседей v. Для σ = (v 1,…, vm), \ dots, v_ )>быть списком отдельных элементов V, для v ∈ V ∖, \ dots, v_ \>>, пусть ν σ (v) (v)>Перечисление вершин в графе называется массивом BFS, если оно является возможным результатом применения BFS к этому графу.<\ displaystyle i>такой, что vi>Возможный результат BFS - это возможный результат гипотезы, которая является результатом возможного решения графа в BFS
Пусть σ = (v 1,…, vn), \ dots, v_ )>будет перечислением вершин V. Перечисление σ называется упорядочением BFS (с источником v 1>), если, для всех 1, vi>- это вершина w ∈ V ∖, \ dots, v_ \>>такие, что ν (v 1,…, vi - 1) (w), \ dots, v_ )>(w)>минимально. Эквивалентно, σ является порядком BFS, если для всех 1 ≤ i с vi ∈ N (vk) ∖ N (vj) \ in N (v_ ) \ setminus N (v_ )>, существует сосед vm>быть соседом v, если такой i существует, и в противном случае быть ∞.<\ displaystyle v_>из vj
Applications
такой, что m .
- Копирование сборки мусора, алгоритм Чейни
- Поиск кратчайшего пути между двумя узлами u и v, длина пути измеряется количество ребер (преимущество перед поиском в глубину )
- (обратный) Cuthill – McKee нумерация сетки
- метод Форда – Фулкерсона для вычисления максимального потока в потоковая сеть
- Сериализация / десериализация двоичного дерева по сравнению с сериализацией в отсортированном порядке, позволяет эффективно реконструировать дерево.
- Построение функции отказа Ахо-Ко rasick сопоставление с образцом.
- Проверка двудольности графа.