def wave1(graph, start): """ Хвильовий алгоритм, що використовує масив відстаней від стартової точки до поточної для визначення чи була вже відвідана вершина :param graph: Граф :param start: Вершина з якої починається обхід :return: Список відстаней від стартової верниши до кожної вернини графа """ q = Queue() q.enqueue(start) # Введемо масив, що буде містити # відстані від стартової вершини start. # Ініціалізуємо масив значеннями -1 (тобто нескінченність) distances = [-1] * len(graph) distances[start] = 0 # Відстань від стартової точки до себе нуль. while not q.empty(): current = q.dequeue() # Беремо перший елемент з черги # Додаємо в чергу всіх сусідів поточного елементу for neighbour in graph[current].neighbors(): if distances[neighbour] == -1: # які ще не були відвідані q.enqueue(neighbour) distances[neighbour] = distances[current] + 1 return distances
def wave2(graph: GraphForAlgorithms, start: int): """ Функція, що запускає хвильовий алгоритм. Використовує граф класу GraphForAlgorithms, вершини якого містять допоміжну інформацію. Функція модифікує вхідний граф, так, що в результаті його всі вершини містять інформацію про найкоротшу відстань від заданої стартової вершини. :param graph: Граф, вершини якого містять відстань від початкової вершини :param start: Стартова вершина, тобто з якої починається робота хвильового алгоритму :return: None """ # Ініціалізуємо додаткову інформацію у графі для роботи алгоритму. for vertex in graph: vertex.set_unvisited() # вершина ще не була відвідана # Відстань у старотовій вершині (тобто від стартової вершини до себе) визначається як 0 graph[start].set_distance(0) q = Queue() # Створюємо чергу q.enqueue(start) # Додаємо у чергу початкову вершину while not q.empty(): vertex_key = q.dequeue() # Беремо перший елемент з черги vertex = graph[vertex_key] # Беремо вершину за індексом # Для всіх сусідів (за ключами) поточної вершини for neighbor_key in vertex.neighbors(): neighbour = graph[neighbor_key] # Беремо вершину-сусіда за ключем if not neighbour.visited(): # Якщо сусід не був відвіданий q.enqueue(neighbor_key) # додаємо його до черги neighbour.set_distance( vertex.distance() + 1) # Встановлюємо значення відстані у вершині-сусіді
def BFS(graph, start): """ Обхід графа в ширину починаючи з заданої вершини :param graph: Граф :param start: Вершина з якої відбувається запуск обходу в ширину :return: Список, i-й елемент якого містить позначку чи була відвідана i-та вершина """ # Введемо масив, що буде містити ознаку чи відвідали вже вершину. # Ініціалізуємо масив значеннями False (тобто не відвідали) visited = [False] * len(graph) q = Queue() # Створюємо чергу q.enqueue(start) # Додаємо у чергу стартову вершину visited[start] = True # та позначаємо її як відвідану while not q.empty(): # Поки черга не порожня current = q.dequeue() # Беремо перший елемент з черги print(current) # Опрацьовуємо взятий елемент # Додаємо в чергу всіх сусідів поточного елементу for neighbour in graph[current].neighbors(): if not visited[neighbour]: # які ще не були відвідані q.enqueue(neighbour) visited[neighbour] = True # Помічаємо як відвідану return visited
def wave(maze, start, wall_cell): """ функція побудови хвильової матриці для лібіринту P54 зі стартовою точкою start wall_cell - символ, що позначає стіну лабіринта або непрохідну його клітину""" # P54 - матриця лабіринту # start - початкова позиція у лабіринті у вигляді кортежу (рядкок, стовпчик) dx = [-1, 0, 1, 0] dy = [0, -1, 0, 1] # dx = [-1, -1, 0, 1, 1, 1, 0, -1] # dy = [0, -1, -1, -1, 0, 1, 1, 1] n = len(maze) # кількість рядків у матриці P54 m = len(maze[0]) # кількість стовпчиків у матриці P54 # створення та ініціалізація хвильової матриці # такої ж розмірності, що і матриця лабіринту waveMatrix = [] for i in range(n): row = [-1] * m waveMatrix.append(row) # створення та ініціалізація sources-матриці # такої ж розмірності, що і матриця лабіринту sources = [] for i in range(n): row = [None] * m sources.append(row) q = Queue() # Створюємо чергу q.enqueue(start) # Додаємо у чергу координати стартової клітини waveMatrix[start[0]][ start[1]] = 0 # Відстань від стартової клітини до себе нуль while not q.empty(): current = q.dequeue() # Беремо перший елемент з черги i = current[0] # координата поточного рядка матриці j = current[1] # координата поточного стовчика матриці # Додаємо в чергу всі сусідні клітини for k in range(len(dx)): i1 = i + dy[k] # координата рядка сусідньої клітини j1 = j + dx[k] # координата стовпчика сусідньої клітини # які ще не були відвідані та у які можна пересуватися if waveMatrix[i1][j1] == -1 and maze[i1][j1] != wall_cell: q.enqueue((i1, j1)) # Встановлюємо відстань на одиницю більшу ніж для поточної waveMatrix[i1][j1] = waveMatrix[i][j] + 1 # Встановлюємо координати звідки ми прийшли у клітину sources[i1][j1] = (i, j) # Повертаємо хвильову матрицю, та sources-матрицю return waveMatrix, sources
def waySearch(graph, start, end): """ Пошук найкоротшого шляху між двома заданими вершинами графа :param graph: Граф :param start: Початкова вершина :param end: Кінцева вершина :return: Кортеж, що містить список вершин - найкоротший шлях, що сполучає вершини start та end та його вагу """ assert start != end distances = [-1] * len(graph) # Масив відстаней sources = [None] * len(graph) # Масив вершин звідки прийшли q = Queue() # Створюємо чергу q.enqueue(start) # Додаємо у чергу стартову вершину distances[start] = 0 # Відстань від стартової точки до себе нуль. while not q.empty(): current = q.dequeue() # Беремо перший елемент з черги # Додаємо в чергу всіх сусідів поточного елементу for neighbour in graph[current].neighbors(): if distances[neighbour] == -1: # які ще не були відвідані q.enqueue(neighbour) distances[neighbour] = distances[current] + 1 sources[neighbour] = current # Вказуємо для сусіда neighbour, # що ми прийшли з вершини current if sources[end] is None: # шляху не існує return None, INF # будуємо шлях за допомогою стеку stack = Stack() current = end while True: stack.push(current) if current == start: break current = sources[current] way = [] # Послідовність вершин шляху while not stack.empty(): way.append(stack.pop()) # Повертаємо шлях та його довжину return way, distances[end]
def BFS(tree: BinaryTree): """ Обхід бінарного дерева в ширину :param tree: Бінарне дерево :return: None """ q = Queue() q.enqueue(tree) # Додаємо у чергу корінь дерева while not q.empty(): current = q.dequeue() # Беремо перший елемент з черги print(current.node()) # Опрацьовуємо взятий елемент # Додаємо в чергу лівий і правий нащадки поточного вузла if current.has_left(): # якщо поточний вузол має лівого нащадка q.enqueue(current.left_subtree()) # додаємо у чергу лівого нащадка if current.has_right(): # якщо поточний вузол має правого нащадка q.enqueue( current.right_subtree()) # додаємо у чергу правого нащадка
def waySearchByWave(graph: GraphForAlgorithms, start: int, end: int): """ Пошук найкоротшої відстані, використовуючи хвильовий алгоритм :param graph: Граф :param start: Початкова вершина :param end: Кінцева вершина :return: Кортеж, що містить список вершин - найкоротший шлях, що сполучає вершини start та end та його вагу """ # Ініціалізуємо додаткову інформацію у графі для роботи алгоритму. for vertex in graph: vertex.set_unvisited() # вершина ще не була відвідана vertex.set_source( None) # Вершина з якої прийшли по найкорошому шляху невизначена # Відстань у старотовій вершині (тобто від стартової вершини до себе) визначається як 0 graph[start].set_distance(0) q = Queue() # Створюємо чергу q.enqueue(start) # Додаємо у чергу початкову вершину while not q.empty(): vertex_key = q.dequeue() # Беремо перший елемент з черги vertex = graph[vertex_key] # Беремо вершину за індексом # Для всіх сусідів (за ключами) поточної вершини for neighbor_key in vertex.neighbors(): neighbour = graph[neighbor_key] # Беремо вершину-сусіда за ключем if not neighbour.visited(): # Якщо сусід не був відвіданий neighbour.set_distance( vertex.distance() + 1) # Встановлюємо значення відстані у вершині-сусіді # значенням на 1 більшии ніж у поточній вершині neighbour.set_source( vertex_key ) # Встановлюємо для сусідньої вершини ідентифікатор звідки ми прийшли у неї q.enqueue(neighbor_key) # додаємо сусіда до черги return graph.construct_way(start, end) # Повертаємо шлях та його вагу
def wave(graph, start): """ Хвильовий алгоритм :param graph: Граф :param start: Вершина з якої починається обхід :return: Список відстаней від стартової верниши до кожної вернини графа """ # Введемо масив, що буде містити ознаку чи відвідали вже вершину. # Ініціалізуємо масив значеннями False (тобто відвідали) visited = [False] * len(graph) # Введемо масив, що буде містити # відстані від стартової вершини start. # Ініціалізуємо масив значеннями -1 (тобто нескінченність) distances = [-1] * len(graph) q = Queue() # Створюємо чергу q.enqueue(start) # Додаємо у чергу стартову вершину visited[start] = True # та позначаємо її як відвідану distances[start] = 0 # Відстань від стартової точки до себе нуль. while not q.empty(): current = q.dequeue() # Беремо перший елемент з черги # Тут Опрацьовуємо взятий елемент, за необхідності # Додаємо в чергу всіх сусідів поточного елементу for neighbour in graph[current].neighbors(): if not visited[neighbour]: # які ще не були відвідані q.enqueue(neighbour) visited[neighbour] = True # Встановлюємо відстань на одиницю більшу ніж для поточної distances[neighbour] = distances[current] + 1 # Повертаємо масив відстаней від start до всіх вершин графа return distances