Python算法学习[5]—图、遍历、连通、最短路径&代码演练

图、遍历、连通、最短路径&代码演练


图是计算机科学中的一种数据结构,它由节点(顶点)和边组成。在实际应用中,图经常被用来表示复杂系统之间的关系,如社交网络、交通网络等。本文将介绍图的基本概念和应用,并提供Python代码实现。同时,我们还将介绍如何使用深度优先搜索和广度优先搜索遍历图,如何判断图的连通性,以及如何求解最短路径问题。

  1. 图的基本概念
    图由节点(顶点)和边组成,通常用G=(V,E)表示。其中,V为顶点集合,E为边的集合。如果两个顶点之间有一条边,则称这两个顶点是相邻的。无向图中的边没有方向,可以双向移动;有向图中的边有方向,只能单向移动。加权图也是一种常见的图,每条边都带有一个权重值。

下面是一个简单的Python代码,用于实现无向图:

class Graph:
    def __init__(self):
        self.vertices = {}
        self.edges = {}

    def add_vertex(self, vertex):
        if vertex not in self.vertices:
            self.vertices[vertex] = []

    def add_edge(self, v1, v2):
        if v1 not in self.vertices:
            self.add_vertex(v1)
        if v2 not in self.vertices:
            self.add_vertex(v2)
        self.vertices[v1].append(v2)
        self.vertices[v2].append(v1)

    def print_graph(self):
        for v in self.vertices:
            print(v, end=' -> ')
            print(self.vertices[v])

在上述代码中,Graph类表示无向图,其中包含一个字典vertices,用于存储每个顶点及其相邻的顶点列表。add_vertex()方法用来添加顶点,add_edge()方法用来添加边,print_graph()方法用来打印整张图。

  1. 遍历图
    图的遍历是指按照某种顺序依次访问图中的所有顶点。常见的图遍历算法有深度优先搜索和广度优先搜索。

2.1 深度优先搜索
深度优先搜索(DFS)是一种递归方式的图遍历算法,其思路是从起始顶点开始,沿着一条路径不断向下探索直到无法继续为止,然后回溯到上一个节点继续遍历。深度优先搜索可以用来查找是否存在一条路径从起始顶点到目标顶点。

下面是一个简单的Python代码,用于实现深度优先搜索:

def dfs(graph, start, visited=None):
    if visited is None:
        visited = set()
    visited.add(start)
    print(start, end=' ')

    for neighbor in graph.vertices[start]:
        if neighbor not in visited:
            dfs(graph, neighbor, visited)

在上述代码中,dfs()函数接收三个参数:graph表示待遍历的图,start表示起始顶点,visited表示已访问过的顶点集合。如果visited未被初始化,则将其设为空集。接着,将起始顶点加入visited集合,并输出该顶点。然后,遍历与该顶点相邻的顶点,如果该相邻顶点未被访问,则递归调用dfs()函数进行遍历。

2.2 广度优先搜索
广度优先搜索(BFS)是一种迭代方式的图遍历算法,其思路是从起始顶点开始,按层次逐步扩展,先遍历与起始顶点相邻的所有顶点,然后遍历与这些

顶点相邻的所有未访问过的顶点,以此类推直到遍历完成。广度优先搜索可以用来查找两个顶点之间的最短路径。

下面是一个简单的Python代码,用于实现广度优先搜索:

from collections import deque

def bfs(graph, start):
    visited = set()
    queue = deque([start])

    while queue:
        vertex = queue.popleft()
        if vertex not in visited:
            visited.add(vertex)
            print(vertex, end=' ')
            for neighbor in graph.vertices[vertex]:
                if neighbor not in visited:
                    queue.append(neighbor)

在上述代码中,bfs()函数接收两个参数:graph表示待遍历的图,start表示起始顶点。首先,初始化visited集合和queue队列,将起始顶点加入队列。然后,进入循环,每次从队列中取出一个顶点并进行判断,如果该顶点未被访问,则加入visited集合,并输出该顶点。接着,遍历与该顶点相邻的顶点,如果这些相邻顶点未被访问,则加入队列中等待遍历。

  1. 判断图的连通性
    在图论中,一个无向图被称为连通图当且仅当任意两个顶点之间都存在一条路径。如果一个无向图不是连通图,则其被称为非连通图或者不相连的图。判断一个无向图是否为连通图的方法是通过深度优先搜索或广度优先搜索,检查图中是否有未被访问过的顶点。

下面是一个简单的Python代码,用于判断无向图的连通性:

def is_connected(graph):
    visited = set()
    dfs(graph, next(iter(graph.vertices)), visited)
    return len(visited) == len(graph.vertices)

在上述代码中,is_connected()函数接收一个参数graph表示待检查的无向图。首先,初始化visited集合,并对任意一个顶点进行深度优先搜索。然后,比较已访问过的顶点数是否等于图中的顶点数,如果相等则说明该无向图是连通图。

  1. 求解最短路径问题
    求解最短路径问题是指在一个加权图中查找从起始顶点到目标顶点的最短路径。常见的算法有Dijkstra算法和A*算法。

4.1 Dijkstra算法
Dijkstra算法是一种贪心算法,其思路是从起始顶点开始,选择当前距离该顶点最近的未访问过的顶点,并更新与该顶点相邻的顶点的距离值。重复以上步骤直到找到目标顶点或者所有顶点都被访问过。

下面是一个简单的Python代码,用于实现Dijkstra算法:

import heapq

def dijkstra(graph, start, end):
    queue = [(0, start)]
    visited = set()

    while queue:
        (distance, vertex) = heapq.heappop(queue)
        if vertex == end:
            return distance
        if vertex not in visited:
            visited.add(vertex)
            for neighbor, weight in graph.vertices[vertex]:
                heapq.heappush(queue, (distance + weight, neighbor))

    return -1

在上述代码中,dijkstra()函数接收三个参数:graph表示待求解的加权图,start表示起始顶点,end表示目标顶点。首先,初始化priority queue队列和visited集合,将起始顶点加入队列。然后,进入循环,每次从队列中取出一个顶点并进行判断,如果该顶点为目标顶点,则返回距离值。如果该顶点未被访问,则将其加入visited集合,并遍历与该顶点相邻的顶点,更新其距离值并加入队列中等待遍历。最后,如果没有找到目标顶点,则返回-1。

4.2 A算法
A
算法是一种启发式算法,其思路是在Dijkstra算法的基础上加入启发函数,用来估算从当前顶点到目标顶点的距离。根据启发函数的估值,可以优先遍历与目标顶点更接近的顶点,从而提高搜索效率。

下面是一个简单的Python代码,用于实现A*算法:

import heapq

def astar(graph, start, end, heuristic):
    queue = [(0, start)]
    visited = set()

    while queue:
        (distance, vertex) = heapq.heappop(queue)
        if vertex == end:
            return distance
        if vertex not in visited:
            visited.add(vertex)
            for neighbor, weight in graph.vertices[vertex]:
                heapq.heappush(queue, (distance + weight + heuristic(neighbor, end), neighbor))

    return -1

在上述代码中,astar()函数接收四个参数:graph表示待求解的加权图,start表示起始顶点,end表示目标顶点,heuristic表示启发函数。首先,初始化priority queue队列和visited集合,将起始顶点加入队列。然后,进入循环,每次从队列中取出一个顶点并进行判断,如果该顶点为目标顶点,则返回距离值。如果该顶点未被访问,则将其加入visited集合,并遍历与该顶点相邻的顶点,根据启发函数的估值更新其距离值并加入队列中等待遍历。最后,如果没有找到目标顶点,则返回-1。

  1. 总结
    本文介绍了图的基本概念和应用,并提供了Python代码实现。同时,我们还介绍了深度优先搜索和广度优先搜索算法,以及如何判断无向图的连通性和求解最短路径问题。这些算法都是图论中非常重要的基础算法,在实际应用中有着广泛的应用。希望本文能够对读者理解和掌握图论的相关知识有所帮助。
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
以下是利用麻雀搜索算法求解遍历十个目标点的最短路径Python代码: ```python import random import math # 计算两点之间的距离 def distance(city1, city2): x1, y1 = city1 x2, y2 = city2 return math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2) # 计算路径长度 def path_length(path, cities): total = 0 for i in range(len(path) - 1): total += distance(cities[path[i]], cities[path[i + 1]]) return total # 随机生成一条路径 def generate_path(num_cities): path = list(range(num_cities)) random.shuffle(path) return path # 随机生成一只麻雀 def generate_sparrow(num_cities): return generate_path(num_cities) # 取得一只麻雀的邻居 def get_neighbor(sparrow): i = random.randint(0, len(sparrow) - 1) j = random.randint(0, len(sparrow) - 1) neighbor = sparrow.copy() neighbor[i], neighbor[j] = neighbor[j], neighbor[i] return neighbor # 计算一只麻雀的适应度 def fitness(sparrow, cities): return 1 / path_length(sparrow, cities) # 麻雀搜索算法 def sparrow_search(cities, num_sparrows, max_iterations): # 随机生成一些麻雀 sparrows = [generate_sparrow(len(cities)) for i in range(num_sparrows)] # 记录最优解 best_sparrow = sparrows[0] # 迭代 for iteration in range(max_iterations): # 对每只麻雀进行搜索 for sparrow in sparrows: # 取得当前麻雀的邻居 neighbor = get_neighbor(sparrow) # 计算适应度 sparrow_fitness = fitness(sparrow, cities) neighbor_fitness = fitness(neighbor, cities) # 如果邻居更优,则更新当前麻雀 if neighbor_fitness > sparrow_fitness: sparrow = neighbor sparrow_fitness = neighbor_fitness # 如果当前麻雀更优,则更新最优解 if sparrow_fitness > fitness(best_sparrow, cities): best_sparrow = sparrow # 输出当前迭代的最优解 print("Iteration {}: {}".format(iteration, path_length(best_sparrow, cities))) # 返回最优解 return best_sparrow # 测试 num_cities = 10 cities = [(random.uniform(0, 1), random.uniform(0, 1)) for i in range(num_cities)] # 随机生成目标点 targets = random.sample(range(num_cities), 10) # 将目标点按顺序排列 targets.sort() # 将目标点插入到城市列表中 for target in targets: cities[target] = (random.uniform(0, 1), random.uniform(0, 1)) best_path = sparrow_search(cities, num_sparrows=50, max_iterations=1000) print("Best path: {}, length: {}".format(best_path, path_length(best_path, cities))) ``` 在上述代码中,首先定义了一些辅助函数,如计算两点之间的距离、计算路径长度、随机生成一条路径等。然后定义了麻雀搜索算法的几个关键步骤,包括随机生成一些麻雀、对每只麻雀进行搜索、取得当前麻雀的邻居、计算适应度等。接着在测试中随机生成了一些城市,并随机选取了十个目标点,将这些目标点插入到城市列表中。最后调用麻雀搜索算法求解遍历这些目标点的最短路径,并输出最优解的路径和长度。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高山莫衣

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值