首页 > 编程语言 >python --图(树)的存储

python --图(树)的存储

时间:2024-03-31 17:44:18浏览次数:15  
标签:存储 python head -- add cnt 顶点 adj

在蓝桥杯竞赛中,常见的图存储方式包括邻接矩阵、邻接表、链式前向星等。这些存储方式在不同的场景下有着各自的优势和适用性。

邻接矩阵

邻接矩阵是最常见的图的表示方法之一。对于一个有$n$个顶点的图,可以用一个$n \times n$的二维数组来表示。如果图中存在从顶点$i$到顶点$j$的边,则$adj[i][j]$为1,否则为0。邻接矩阵适用于稠密图,但在稀疏图中会占用较多的空间。

例题: 判断图中是否存在从顶点1到顶点3的边。

# 定义邻接矩阵
adj_matrix = [
    [0, 1, 0, 0],
    [0, 0, 1, 0],
    [0, 0, 0, 1],
    [0, 0, 0, 0]
]

if adj_matrix[1][3] == 1:
    print("顶点1到顶点3存在边")
else:
    print("顶点1到顶点3不存在边")

加边

def add_edge(adj_matrix, u, v):
    adj_matrix[u][v] = 1
    adj_matrix[v][u] = 1  # 如果是有向图则不需要这行

邻接表

邻接表是一种更节省空间的表示方法,它用一个数组和若干个链表来表示图。数组的每个元素表示一个顶点,对应的链表存储了从该顶点出发的所有边。邻接表适用于稀疏图,空间复杂度较低。

例题: 判断图中是否存在从顶点1到顶点3的边。

# 定义邻接表
adj_list = {
    1: [2],
    2: [3],
    3: []
}

if 3 in adj_list[1]:
    print("顶点1到顶点3存在边")
else:
    print("顶点1到顶点3不存在边")

加边:

def add_edge(adj_list, u, v):
    if u not in adj_list:
        adj_list[u] = []
    adj_list[u].append(v)

    # 如果是有向图,则不需要下面这行
    if v not in adj_list:
        adj_list[v] = []
    adj_list[v].append(u)

链式前向星

链式前向星是一种用于存储稀疏图的高效表示方法,它通过三个数组来表示图的结构:headnxtto。其中head[u]存储了顶点$u$的第一条边的编号,nxt[i]存储了编号为$i$的边的下一条边的编号,to[i]存储了编号为$i$的边的终点。

例题: 使用链式前向星存储图,并遍历顶点1的所有邻居。

class Edge:
    def __init__(self, to, weight):
        self.to = to
        self.weight = weight
        self.next = None

def add(u, v, weight):
    global cnt
    cnt += 1
    nxt[cnt] = head[u]
    head[u] = cnt
    to[cnt] = v

# 初始化
n = 4
head = [-1] * n
nxt = [0] * n
to = [0] * n
cnt = -1

# 添加边
add(1, 2, 5)
add(1, 3, 3)
add(2, 3, 2)
add(2, 4, 6)
add(3, 4, 7)

# 遍历顶点1的所有邻居
i = head[1]
while i != -1:
    print("顶点1的邻居:", to[i])
    i = nxt[i]

关于链式前向星的详细讲解:(参考这篇博客https://blog.csdn.net/Binary_Heap/article/details/78209086)

点击查看代码
以下是对原文的Python讲解:

前向星是一种特殊的边集数组,我们按照起点从小到大排序,如果起点相同就按照终点从小到大排序,并记录下以某个点为起点的所有边在数组中的起始位置和存储长度,那么前向星就构造好了。

用`len[i]`来记录所有以i为起点的边在数组中的存储长度。

用`head[i]`记录以i为边集在数组中的第一个存储位置。

举个例子:

我们输入边的顺序为:

1 2
2 3
3 4
1 3
4 1
1 5
4 5


那么排完序后就得到:

编号: 1 2 3 4 5 6 7
起点u: 1 1 1 2 3 4 4
终点v: 2 3 5 3 4 1 5


得到:

head[1] = 1 len[1] = 3
head[2] = 4 len[2] = 1
head[3] = 5 len[3] = 1
head[4] = 6 len[4] = 2


但是利用前向星会有排序操作,如果用快排时间至少为O(nlog(n))。

如果用链式前向星,就可以避免排序。

我们建立边结构体为:

```python
class Edge:
    def __init__(self, to, w):
        self.next = None
        self.to = to
        self.w = w

另外还有一个数组head[],它是用来表示以i为起点的第一条边存储的位置,实际上你会发现这里的第一条边存储的位置其实在以i为起点的所有边的最后输入的那个编号。

head[]数组一般初始化为-1,对于加边的add函数是这样的:

def add(u, v, w):
    global cnt
    edge[cnt].w = w
    edge[cnt].to = v
    edge[cnt].next = head[u]
    head[u] = cnt
    cnt += 1

初始化cnt = 0,这样,现在我们还是按照上面的图和输入来模拟一下:

# 初始化
cnt = 0
edge = [Edge(0, 0) for _ in range(7)]
head = [-1] * 6

# 加边
add(1, 2, 0)
add(2, 3, 0)
add(3, 4, 0)
add(1, 3, 0)
add(4, 1, 0)
add(1, 5, 0)
add(4, 5, 0)

很明显,head[i]保存的是以i为起点的所有边中编号最大的那个,而把这个当作顶点i的第一条起始边的位置。

这样在遍历时是倒着遍历的,也就是说与输入顺序是相反的,不过这样不影响结果的正确性。

比如以上图为例,以节点1为起点的边有3条,它们的编号分别是0, 3, 5,而head[1] = 5

我们在遍历以u节点为起始位置的所有边的时候是这样的:

u = 1
i = head[u]
while i != -1:
    print("起点为{}的边的终点是{},权重为{}".format(u, edge[i].to, edge[i].w))
    i = edge[i].next

这样就可以正确地遍历出以节点1为起始位置的所有边。

</details>
以上是在Python中常见的图存储方式及其应用例题。在蓝桥杯竞赛中,图相关的题目往往涉及到图的存储、遍历、最短路径、最小生成树等基本算法和数据结构。掌握这些常见的图存储方式对于解决相关问题非常重要。

标签:存储,python,head,--,add,cnt,顶点,adj
From: https://www.cnblogs.com/taixian/p/18106988

相关文章

  • springboot 监听请求
    加个这个类就可以了importorg.springframework.stereotype.Component;importjavax.servlet.*;importjavax.servlet.http.HttpServletRequest;importjava.io.BufferedReader;importjava.io.IOException;@ComponentpublicclassLoggingFilterimplementsFilter{@Overri......
  • 3.31
    所花时间:5小时代码量:154博客篇:1地铁起点到终点的最短路径查询:使用广度优先遍历,当要访问该站点时先储存在队列,最后出队形式访问每次访问传入数据:name:站点名;now:之前访问的站点字符串总和;nowline:当前站点的线路;ed:要到达的站点名称;i:当前经过站数以及字符串的数组下标;s:当前......
  • 111
    1.回顾你过去将近3年的学习经历当初你报考的时候,是真正喜欢计算机这个专业吗?作为一个学生,回顾我过去将近三年的学习经历是一段充满挑战和成长的旅程。当初我报考计算机专业时,我对计算机确实有着浓厚的兴趣。我喜欢探索新技术,解决问题,并且觉得计算机领域充满了无限的可能性。在......
  • 前端可视化echarts和three
    canvas画一条直线constcanvas=document.getElementById('canvas')constctx=canvas.getContext('2d')ctx.beginPath()//绘制都用beginPath和closePath包裹ctx.lineWidth=4ctx.strokeStyle='orange'//起点终点中间点ctx.moveTo......
  • MySQL面试必备一之索引
    本文首发于公众号:Hunter后端原文链接:MySQL面试必备一之索引在面试过程中,会有一些关于MySQL索引相关的问题,以下总结了一些:MySQL的数据存储使用的是什么索引结构B+树的结构是什么样子什么是复合索引、聚簇索引、覆盖索引什么是最左匹配原则数据B+树中是如何查询的......
  • bindview.js 的使用
    快速入门1.创建第一个应用由于该库还不支持src引入,接下来的例子我将在webpack环境下演示,webpack模板已经配置完毕,可直接下载使用创建一个应用可用通过new来创建实例或通过提供的createApp方法来创建下面我将分别演示通过new来创建App,el配置项用来选择DOM......
  • input子系统三
    参考资料:正点原子Linux设备驱动韦东山第二期 图来源于100ask: 一个设备链表,一个handler链表,左边是设备层,右侧是handler处理层,用来处理各种事件。handler处理层内核已经做好了。驱动一个Input设备只需要构造一个input_dev,核心层来注册input_dev和注册input_handler就可以......
  • 111
    请阅读北航陈彦吉同学的这篇博客中(地址:https://www.cnblogs.com/ChildishChange/p/7363123.html)的各参考资料,并回答如下问题:1.回顾你过去将近3年的学习经历当初你报考的时候,是真正喜欢计算机这个专业吗?你现在后悔选择了这个专业吗?你认为你现在最喜欢的领域是什么(可以是计算机......
  • 思考
     从去年的某个时间开始,我多了很多思考,很多时候突然就进入了某段思考,也许是看见了某个人、某件事、某种现象,或者就是无来由的开始思考。思考人、自然、社会。 很多以前认为很常规的东西都引发了我的思考,为什么是这样,社会为什么这样运行,很多现象背后的深层本质是什么。我观察......
  • 周报
    这一周就是打打比赛,除了日常的训练外,还有自己打的一些牛客,cf的题。周二天梯7-7估值一亿的AI核心代码这道题写的很痛苦,写了两个小时,导致其他的题都没有写,写的时候就是感觉能写出来,随着写的过程中发现细节越难越难处理,代码越来越长。交了之后居然都错了。。。挺无语的。includ......