1. 什么是图?
- 图结构是一种与树结构相似的数据结构
- 图论是数学的一个分支,并且在数学的概念上,树也是图的一种
- 他以图为研究对象,研究的顶点和边组成的图形
- 主要研究事物之间的关系,顶点代表事物,边代表两个事物之间的关系
2. 图的应用场景
- 我们要知道树结构有很多应用场景,比如公司的架构、家族的关系等
- 图结构的话,有人与人之间的关系网,人就代表顶点,人与人之间的关系就代表边
- 科学家们在观察人与人之间关系网的时候,还发现了六度空间理论
3. 六度空间理论
- 你和任何一个陌生人之间所间隔的人不会超过六个
- 最多通过6个中间人你就能够认识任何一个陌生人。这就是六度分割理论,也叫小世界理论。
4. 图的特点
- 一组顶点:通常用V(Vertex)表示顶点的集合
- 一组边:通常用E(Edge)来表示边的集合
- 边是顶点与顶点之间的连线
- 边可以是有向的,也可以是无向的
- 比如A — B 通常表示无向,A --> B 通常表示有向
- 无向就是A可以到B,B可以到A,有向就是A可以到B,但B不能到A
5. 欧拉七桥问题
- 18世纪初普鲁士的哥尼斯堡,有一条河穿过,河上有两个小岛,有七座桥把两个岛与河岸联系起来。有个人提出一个问题:一个步行者怎样才能不重复、不遗漏地一次走完七座桥,最后回到出发点。
- 后来大数学家欧拉把它转化成一个几何问题——一笔画问题。他不仅解决了此问题,且给出了连通图可以一笔画的充要条件是:奇点的数目不是0个就是2个(连到一点的数目如是奇数条,就称为奇点,如果是偶数条就称为偶点,要想一笔画成,必须中间点均是偶点,也就是有来路必有另一条去路,奇点只可能在两端,因此任何图能一笔画成,奇点要么没有要么在两端)
6. 图的术语
- 顶点
- 边
- 相邻顶点
- 度
- 路径
- 简单路径:就是一个顶点到另一个顶点中,没有重复的顶点
- 回路:有重复的顶点
- 无向图
- 有向图
- 无权图
- 带权图
- 边有一定的权重,这里的权重可以是任意你希望表示的数据,比如距离、花费的时间、票价等
7. 图的表示(存储)
7.1 邻接矩阵

- 邻接矩阵是采用二维数组来表示顶点之间的连线
- 在二维数组中,0表示没有连线,1表示有连线
- 邻接矩阵的问题:
- 邻接矩阵有一个比较严重的问题,就是如果是一个稀疏图(顶点之间的边比较少)
- 那么矩阵中将存在大量的0,需要浪费大量的空间来存储根本不存在的边
7.2 邻接表

- 邻接表是当前顶点和它相邻顶点组成的列表(顶点列表)
- 这个列表的存储方式有很多,数组、链表、哈希表都可以
- 邻接表的问题:
- 邻接图计算出度是比较简单的(出度:指向别人的数量)
- 邻接表如果需要计算入度,那么是一件非常麻烦的事情(入度:别人指向自己的数量)
- 它必须构造一个逆邻接表,才有有效的计算入度
8. 图的封装
8.1 广度优先遍历(BFS
)

initializeColor() {
let colors = {}
for (let i = 0; i < this.vertexs.length; i++) {
colors[this.vertexs[i]] = "white"
}
return colors
}
bfs(firstV) {
let colors = this.initializeColor()
let queue = []
let resultStr = ""
queue.push(firstV)
colors[firstV] = "black"
while (queue.length != 0) {
let v = queue.shift()
resultStr += v + " "
let edges = this.edges[v]
for (let i = 0; i < edges.length; i++) {
if (colors[edges[i]] == "white") {
queue.push(edges[i])
colors[edges[i]] = "black"
}
}
}
return resultStr
}
8.2 深度优先遍历(DFS
)

initializeColor() {
let colors = {}
for (let i = 0; i < this.vertexs.length; i++) {
colors[this.vertexs[i]] = "white"
}
return colors
}
dfs(firstV) {
let colors = this.initializeColor()
let stack = []
let resultStr = ""
stack.push(firstV)
colors[firstV] = "black"
while (stack.length != 0) {
let v = stack.pop()
resultStr += v + " "
let edges = this.edges[v]
for (let i = 0; i < edges.length; i++) {
if (colors[edges[i]] == "white") {
stack.push(edges[i])
colors[edges[i]] = "black"
}
}
}
return resultStr
}
8.3 封装图类
class Graph {
constructor() {
this.vertexs = []
this.edges = {}
}
addVertex(v) {
this.vertexs.push(v)
this.edges[v] = []
}
addEdge(v1, v2) {
this.edges[v1].push(v2)
this.edges[v2].push(v1)
}
toString() {
let resultStr = ""
for (let i = 0; i < this.vertexs.length; i++) {
let vertex = this.vertexs[i]
resultStr += vertex + " --> "
for (let j = 0; j < this.edges[vertex].length; j++) {
let edge = this.edges[vertex][j]
resultStr += edge + " "
}
resultStr += "\n"
}
return resultStr
}
initializeColor() {
let colors = {}
for (let i = 0; i < this.vertexs.length; i++) {
colors[this.vertexs[i]] = "white"
}
return colors
}
bfs(firstV) {
let colors = this.initializeColor()
let queue = []
let resultStr = ""
queue.push(firstV)
colors[firstV] = "black"
while (queue.length != 0) {
let v = queue.shift()
resultStr += v + " "
let edges = this.edges[v]
for (let i = 0; i < edges.length; i++) {
if (colors[edges[i]] == "white") {
queue.push(edges[i])
colors[edges[i]] = "black"
}
}
}
return resultStr
}
dfs(firstV) {
let colors = this.initializeColor()
let stack = []
let resultStr = ""
stack.push(firstV)
colors[firstV] = "black"
while (stack.length != 0) {
let v = stack.pop()
resultStr += v + " "
let edges = this.edges[v]
for (let i = 0; i < edges.length; i++) {
if (colors[edges[i]] == "white") {
stack.push(edges[i])
colors[edges[i]] = "black"
}
}
}
return resultStr
}
}
let graph = new Graph()
let arr = ["A", "B", "C", "D", "E", "F", "G", "H", "I"]
for (let i = 0; i < arr.length; i++) {
graph.addVertex((arr[i]))
}
graph.addEdge("A", "B")
graph.addEdge("A", "C")
graph.addEdge("A", "D")
graph.addEdge("C", "D")
graph.addEdge("C", "G")
graph.addEdge("D", "G")
graph.addEdge("D", "H")
graph.addEdge("B", "E")
graph.addEdge("B", "F")
graph.addEdge("E", "I")
console.log(graph.toString())
console.log(graph.dfs("A"));
console.log(graph);