BFS(考虑非连通图)

实验内容

针对图,根据给定的数据选择合适的存储方式(邻接矩阵和邻接表中的一种)进行存储(存储方式选择也是实验的检查内容之一),并进行图的广度优先遍历的过程。
数据集 1:使用 data.txt 中的数据,看做无向图,选择合适的方式进行存储(提示:其特征为节点数较少而边比较密集),并以 A 为起始顶点输出遍历过程。
数据集 2:twitter_small: Nodes 81306, Edges 1768149, 有向图;
twitter_large: Nodes 11316811, Edges 85331846, 有向图。
对 twitter_small,选择一种合适的存储方式存储数据,并输出 BFS 的遍历时间。twitter_large 不做要求。
提示:图可能不是连通图,且可能有重复边。

算法设计思路

数据集1

由于实验要求中已经说明,data中的图节点数较少且边比较密集所以采用邻接矩阵的存储方式,由于数据集规模较小,所以直接初始化一个矩阵对数据进行读取,若两个点之间存在边,将对应矩阵位置的值设为1即可得到邻接矩阵,然后实现BFS函数对图进行遍历即可。

数据集2

  1. 首先,定义一个BFS类,其中包含构造函数__init__和BFS遍历方法bfs
  2. 在构造函数__init__中,初始化一个空的visited集合,用于记录已访问的节点。
  3. 在BFS遍历方法bfs中,接受起始节点start_node作为输入参数。
  4. 初始化一个队列queue,将起始节点start_node放入队列中,并将其添加到visited集合中。
  5. 当队列queue不为空时,执行以下循环:
    • 弹出队列中的第一个节点node
    • 遍历节点node的邻居节点neighbor
      • 如果neighbor不在visited集合中,则将其添加到队列queue中,并将其添加到visited集合中。
  6. do方法中,接受邻接表adj_list和所有节点集合all_nodes作为输入参数。
  7. 将输入的邻接表和所有节点集合赋值给BFS对象的属性adj_listall_nodes
  8. 初始化一个空的traversal_times列表,用于存储每次遍历的时间。
  9. 对所有节点进行遍历:
    • 如果节点不在visited集合中,则执行以下操作:
      • 记录遍历前的visited集合长度l1
      • 记录遍历开始的时间start_time
      • 调用BFS对象的bfs方法进行BFS遍历。
      • 记录遍历结束的时间end_time
      • 计算本次遍历的时间traversal_time(即end_time - start_time)。
      • 记录遍历后的visited集合长度l2
      • 将本次遍历的时间traversal_time添加到traversal_times列表中。
  10. 输出总节点数(visited集合的长度)和总遍历时间(traversal_times列表中所有时间的总和)。

源码及注释

BFS_1

with open('data.txt', 'r') as file:
    lines = file.readlines()
nodes = lines[0].strip().split(',')
node_index = {node: index for index, node in enumerate(nodes)}
num_nodes = len(nodes)
adj_matrix = [[0] * num_nodes for _ in range(num_nodes)]
# 构建邻接矩阵
for line in lines[1:]:
    node1, node2 = line.strip().split('-')
    index1 = node_index[node1]
    index2 = node_index[node2]
    adj_matrix[index1][index2] = 1
    adj_matrix[index2][index1] = 1

# 输出邻接矩阵
for row in adj_matrix:
    print(row)
from collections import deque

def bfs(graph, start_node):
    visited = [False] * len(graph)
    queue = deque()

    # 将起始节点放入队列并标记为已访问
    queue.append(start_node)
    visited[start_node] = True

    while queue:
        node = queue.popleft()
        print(nodes[node], end=' ')

        # 遍历与当前节点相邻的未访问节点
        for neighbor in range(len(graph[node])):
            if graph[node][neighbor] == 1 and not visited[neighbor]:
                queue.append(neighbor)
                visited[neighbor] = True

# 以A为起始顶点进行BFS遍历
start_node = node_index['A']
bfs(adj_matrix, start_node)

BFS_2

import time
from collections import defaultdict

class BFS():
    def __init__(self) -> None:
        self = self
        visited = set()
        self.visited = visited
        
    def bfs(self,start_node):
        queue = [start_node]
        self.visited.add(start_node)

        while queue:
            node = queue.pop(0)
            # 处理当前节点
            #print(node)
            for neighbor in self.adj_list[node]:
                if neighbor not in self.visited:
                    queue.append(neighbor)
                    self.visited.add(neighbor)
    
    
    def do(self,adj_list,all_nodes):
        self.adj_list = adj_list
        self.all_nodes = all_nodes
        # 遍历所有节点
        traversal_times = []
        for node in all_nodes:
            if node not in self.visited:
                l1 = len(self.visited)
                start_time = time.time()
                BFS.bfs(self,start_node=node)
                end_time = time.time()
                l2 = len(self.visited)
                traversal_time = end_time - start_time
                print("本次BFS遍历时间:", traversal_time, "秒")
                print("本次遍历点数:",l2-l1)
                traversal_times.append(traversal_time)
                
        print("总节点数:", len(self.visited))
        print("总遍历时间:", sum(traversal_times), "秒")        
                
# 读取数据集文件
with open('twitter_small.txt', 'r') as file:
    lines = file.readlines()

# 构建邻接表
adj_list = defaultdict(list)
all_nodes = set()
for line in lines:
    node1, node2 = map(int, line.strip().split())
    adj_list[node1].append(node2)
    all_nodes.add(node1)
    all_nodes.add(node2)

B = BFS()
B.do(adj_list,all_nodes)

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值