lufei's Studio.

数据结构-图(graph)

字数统计: 1.2k阅读时长: 7 min
2021/04/09 Share

本文简单的介绍一下 图(Graph) ,总结一下,方便记忆。

若干定义

  • 一个图由顶点(vertex)集和边(edge)集组成。简写成:G = (V, E)。

  • 每一条 edge 就是一个点对,比如(v ,w),v,w 是顶点集 V 中的顶点。

  • 有时,也把 edge 称为弧(arc)。

  • 如果这个点对是有序的,那么图就是有向的(directed)。

  • 有向的图有时也叫做有向图(digraph)。

  • 如果 edge(v,w)属于 边集 E,那么就称顶点 v,W 邻接。

  • 有时候,edge 还有第三种成分,称作权(weight)或值(cost)。

图的表示方法

  • 使用一个二维数组来表示,称为邻接矩阵(adjacency matrix)表示法

  • 邻接表(adjacency list)

实现一个简单的 graph (swift 版)

先实现 Vertex

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public struct Vertex<T>: Equatable where T: Hashable {

public var data: T
public let index: Int

}

extension Vertex: CustomStringConvertible {

public var description: String {
return "\(index): \(data)"
}

}

extension Vertex: Hashable {

public func hasher(into hasher: inout Hasher) {
hasher.combine(data)
hasher.combine(index)
}

}

public func ==<T>(lhs: Vertex<T>, rhs: Vertex<T>) -> Bool {
guard lhs.index == rhs.index else {
return false
}

guard lhs.data == rhs.data else {
return false
}

return true
}

然后实现 Edge

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public struct Edge<T>: Equatable where T: Hashable {

public let from: Vertex<T>
public let to: Vertex<T>

public let weight: Double?

}

extension Edge: CustomStringConvertible {

public var description: String {
guard let unwrappedWeight = weight else {
return "\(from.description) -> \(to.description)"
}
return "\(from.description) -(\(unwrappedWeight))-> \(to.description)"
}

}

extension Edge: Hashable {

public func hash(into hasher: inout Hasher) {
hasher.combine(from)
hasher.combine(to)
if weight != nil {
hasher.combine(weight)
}
}

}

public func == <T>(lhs: Edge<T>, rhs: Edge<T>) -> Bool {
guard lhs.from == rhs.from else {
return false
}

guard lhs.to == rhs.to else {
return false
}

guard lhs.weight == rhs.weight else {
return false
}

return true
}

实现抽象 graph 基类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
open class AbstractGraph<T>: CustomStringConvertible where T: Hashable {

public required init() {}

public required init(fromGraph graph: AbstractGraph<T>) {
for edge in graph.edges {
let from = createVertex(edge.from.data)
let to = createVertex(edge.to.data)

addDirectedEdge(from, to: to, withWeight: edge.weight)
}
}

open var description: String {
fatalError("abstract property accessed")
}

open var vertices: [Vertex<T>] {
fatalError("abstract property accessed")
}

open var edges: [Edge<T>] {
fatalError("abstract property accessed")
}

// Adds a new vertex to the matrix.
// Performance: possibly O(n^2) because of the resizing of the matrix.
open func createVertex(_ data: T) -> Vertex<T> {
fatalError("abstract function called")
}

open func addDirectedEdge(_ from: Vertex<T>, to: Vertex<T>, withWeight weight: Double?) {
fatalError("abstract function called")
}

open func addUndirectedEdge(_ vertices: (Vertex<T>, Vertex<T>), withWeight weight: Double?) {
fatalError("abstract function called")
}

open func weightFrom(_ sourceVertex: Vertex<T>, to destinationVertex: Vertex<T>) -> Double? {
fatalError("abstract function called")
}

open func edgesFrom(_ sourceVertex: Vertex<T>) -> [Edge<T>] {
fatalError("abstract function called")
}
}

使用邻接表来表示 graph

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
private class EdgeList<T> where T: Hashable {

var vertex: Vertex<T>
var edges: [Edge<T>]?

init(vertex: Vertex<T>) {
self.vertex = vertex
}

func addEdge(_ edge: Edge<T>) {
edges?.append(edge)
}

}

open class AdjacencyListGraph<T>: AbstractGraph<T> where T: Hashable {

fileprivate var adjacencyList: [EdgeList<T>] = []

public required init() {
super.init()
}

public required init(fromGraph graph: AbstractGraph<T>) {
super.init(fromGraph: graph)
}

open override var vertices: [Vertex<T>] {
var vertices = [Vertex<T>]()
for edgeList in adjacencyList {
vertices.append(edgeList.vertex)
}
return vertices
}

open override var edges: [Edge<T>] {
var allEdges = Set<Edge<T>>()
for edgeList in adjacencyList {
guard let edges = edgeList.edges else {
continue
}

for edge in edges {
allEdges.insert(edge)
}
}
return Array(allEdges)
}

open override func createVertex(_ data: T) -> Vertex<T> {
// check if the vertex already exists
let matchingVertices = vertices.filter { vertex in
return vertex.data == data
}

if matchingVertices.count > 0 {
return matchingVertices.last!
}

// if the vertex doesn't exist, create a new one
let vertex = Vertex(data: data, index: adjacencyList.count)
adjacencyList.append(EdgeList(vertex: vertex))
return vertex
}

open override func addDirectedEdge(_ from: Vertex<T>, to: Vertex<T>, withWeight weight: Double?) {
// works
let edge = Edge(from: from, to: to, weight: weight)
let edgeList = adjacencyList[from.index]
if edgeList.edges != nil {
edgeList.addEdge(edge)
} else {
edgeList.edges = [edge]
}
}

open override func addUndirectedEdge(_ vertices: (Vertex<T>, Vertex<T>), withWeight weight: Double?) {
addDirectedEdge(vertices.0, to: vertices.1, withWeight: weight)
addDirectedEdge(vertices.1, to: vertices.0, withWeight: weight)
}

open override func weightFrom(_ sourceVertex: Vertex<T>, to destinationVertex: Vertex<T>) -> Double? {
guard let edges = adjacencyList[sourceVertex.index].edges else {
return nil
}

for edge: Edge<T> in edges {
if edge.to == destinationVertex {
return edge.weight
}
}

return nil
}

open override func edgesFrom(_ sourceVertex: Vertex<T>) -> [Edge<T>] {
return adjacencyList[sourceVertex.index].edges ?? []
}

open override var description: String {
var rows = [String]()
for edgeList in adjacencyList {

guard let edges = edgeList.edges else {
continue
}

var row = [String]()
for edge in edges {
var value = "\(edge.to.data)"
if edge.weight != nil {
value = "(\(value): \(edge.weight!))"
}
row.append(value)
}

rows.append("\(edgeList.vertex.data) -> [\(row.joined(separator: ", "))]")
}

return rows.joined(separator: "\n")
}
}

参考

Graph

CATALOG
  1. 1. 若干定义
  2. 2. 图的表示方法
  3. 3. 实现一个简单的 graph (swift 版)
  4. 4. 参考