1、定义
图的构成:顶点和边
无向边:顶点 V i V_i Vi 和 V j V_j Vj 之间的边没有方向,用无序偶表示 ( V i , V j ) (V_i,V_j) (Vi,Vj)
有向边:顶点 V i V_i Vi 和 V j V_j Vj 之间的边有方向,又称为弧,用有序偶 < V i , V j > <V_i,V_j> <Vi,Vj> 表示
简单图:不存在顶点到自身的边,且不存在重复的边,这样的图称为简单图
无向完全图:任意两个顶点之间都存在边的无向图,共有 n ∗ ( n − 1 ) 2 \frac{n*(n-1)}{2} 2n∗(n−1) 条边
有向完全图:任意两个顶点之间都存在方向相反的两条弧的有向图,共有 n ∗ ( n − 1 ) n*(n-1) n∗(n−1) 条弧
稀疏图和稠密图:边或弧数小于 n l o g 2 n nlog_2n nlog2n 的图称为稀疏图,否则称为稠密图
顶点的度( T D TD TD):是与顶点相关联的边的数目
- 入度( I D ID ID):以该顶点为头的弧数
- 出度( O D OD OD):以该顶点为尾的弧数
- T D = I D + O D TD = ID+OD TD=ID+OD
连通图:无向图中顶点 V 1 V_1 V1 到顶点 V 2 V_2 V2 有路径,则称 V 1 V_1 V1 和 V 2 V_2 V2 是连通的,如果无向图中任意两个顶点是连通的,则称该图为连通图
连通分量:无向图中的极大连通子图称为连通分量
强连通图:有向图中每一对顶点都存在路径,则称该图为强连通图
强连通分量:有向图中的极大强连通子图称为强连通分量
生成树:连通图的极小连通子图,含有图的全部 n n n 个顶点,但是只有 n − 1 n-1 n−1 条边
2、图的存储
- 邻接矩阵:一维数组存储顶点信息,二维数组存储边或弧的信息
缺点: 当边或弧的数目较少时,会造成较大的存储空间的浪费 - 邻接表:一维数组存储顶点信息,每个顶点的所有邻接点用单链表存储
缺点:对有向图的处理,有时需要再建立一个逆邻接表 - 十字链表
- ==邻接多重表 ==
3、图的遍历
3.1、深度优先遍历
GRAPH = {
'A': ['B', 'F'],
'B': ['C', 'I', 'G'],
'C': ['B', 'I', 'D'],
'D': ['C', 'I', 'G', 'H', 'E'],
'E': ['D', 'H', 'F'],
'F': ['A', 'G', 'E'],
'G': ['B', 'F', 'H', 'D'],
'H': ['G', 'D', 'E'],
'I': ['B', 'C', 'D'],
}
Searched = set() # 记录访问过的顶点
def dfs(graph, start):
if start not in Searched:
print(start)
Search.add(start)
for node in graph[start]:
if node not in Searched:
dfs(graph, node)
def dfs_use_stack(graph, start):
stack = []
stack.append(start)
searched = set()
while stack:
cur_node = stack.pop()
if cur_node not in searched:
print(cur_node)
searched.add(cur_node)
# for node in reversed(graph[cur_node]):
for node in graph[cur_node]:
stack.append(node)
3.2、广度优先遍历
def bfs(graph, start):
queue = []
queue.append(start)
Searched = set()
while queue:
cur_node = queue.pop(0) # 队列 FIFO
if cur_node not in Searched:
print(cur_node)
Searched.add(cur_node)
for node in graph[cur_node]:
queue.append(node)