addNode (node) {
if
(!
this
.
adjacencyList
.
has
(node)) {
this
.
adjacencyList
.
set
(node, []);
}
else
{
throw
new
Error
(
'节点已存在'
)
* 添加边
* to 节点1
* form 节点2
addEdge (to,
from
) {
this
.
adjacencyList
.
has
(to) &&
this
.
adjacencyList
.
has
(
from
)
let
toAdjacent =
this
.
adjacencyList
.
get
(to)
let
fromAdjacent =
this
.
adjacencyList
.
get
(
from
)
toAdjacent = [...
new
Set
([...toAdjacent,
from
])];
fromAdjacent = [...
new
Set
([...fromAdjacent, to])];
this
.
adjacencyList
.
set
(to, toAdjacent);
this
.
adjacencyList
.
set
(
from
, fromAdjacent);
print () {
const
nodes =
this
.
adjacencyList
.
keys
();
for
(
let
node
of
nodes) {
const
neighbors =
this
.
adjacencyList
.
get
(node);
const
neighborsString = neighbors.
join
(
' '
);
console
.
log
(
`节点
${node}
, 相邻节点
${neighborsString}
`
);
创建图的示例
const
graph =
new
Graph
()
graph.
addNode
(
'A'
)
graph.
addNode
(
'B'
)
graph.
addNode
(
'C'
)
graph.
addNode
(
'D'
)
graph.
addNode
(
'E'
)
graph.
addNode
(
'F'
)
graph.
addEdge
(
'A'
,
'B'
)
graph.
addEdge
(
'A'
,
'D'
)
graph.
addEdge
(
'A'
,
'E'
)
graph.
addEdge
(
'B'
,
'A'
)
graph.
addEdge
(
'B'
,
'C'
)
graph.
addEdge
(
'C'
,
'B'
)
graph.
addEdge
(
'C'
,
'E'
)
graph.
addEdge
(
'C'
,
'F'
)
graph.
addEdge
(
'D'
,
'A'
)
graph.
addEdge
(
'D'
,
'E'
)
graph.
addEdge
(
'E'
,
'A'
)
graph.
addEdge
(
'E'
,
'C'
)
graph.
addEdge
(
'E'
,
'D'
)
graph.
addEdge
(
'E'
,
'F'
)
graph.
addEdge
(
'F'
,
'C'
)
graph.
addEdge
(
'F'
,
'E'
)
graph.
print
()
图的广度优先遍历(BFS)
* 无向图
class
Graph
{
* 图的广度优先遍历
* node 遍历的起点
bfs (node) {
if
(
this
.
adjacencyList
.
has
(node)) {
const
result = [];
const
hash = {};
const
queue = [];
const
nodes =
this
.
adjacencyList
.
keys
();
for
(
let
node
of
nodes) {
hash[node] =
false
;
hash[node] =
true
;
queue.
push
(node);
result.
push
(node);
while
(queue.
length
>
0
) {
let
q = queue.
shift
();
let
list =
this
.
adjacencyList
.
get
(q);
for
(
let
i =
0
; i < list.
length
; i++) {
let
temp = list[i]
if
(!hash[temp]) {
result.
push
(temp)
hash[temp] =
true
queue.
push
(temp)
return
result;
return
null
图的深度优先遍历(DFS)
* 无向图
class
Graph
{
* 图的深度优先遍历
* node 遍历的起点
dfs (node) {
const
result = [];
const
hash = {};
const
nodes =
this
.
adjacencyList
.
keys
();
for
(
let
node
of
nodes) {
hash[node] =
false
;
const
DFS
= (
node
) => {
let
list =
this
.
adjacencyList
.
get
(node);
for
(
let
i =
0
; i < list.
length
; i++) {
let
temp = list[i];
if
(!hash[temp]) {
hash[temp] =
true
;
result.
push
(temp);
DFS
(temp);
if
(
this
.
adjacencyList
.
has
(node)) {
hash[node] =
true
;
result.
push
(node);
DFS
(node);
return
result;
return
null
;
领接矩阵的实现
* 无向图
class
Graph
{
constructor
() {
this
.
matrix
= [];
* 添加节点
addNode () {
this
.
matrix
.
push
([]);
const
L =
this
.
matrix
.
length
;
for
(
let
i =
0
; i < L; i++) {
let
start =
this
.
matrix
[i].
length
;
while
(start < L) {
this
.
matrix
[i][start] =
0
;
start +=
1
* 添加边
addEdge (to,
from
) {
(to <
this
.
matrix
.
length
&& to >=
0
) &&
(
from
<
this
.
matrix
.
length
&&
from
>=
0
)
this
.
matrix
[to][
from
] =
1
;
this
.
matrix
[
from
][to] =
1
;
print () {
const
L =
this
.
matrix
.
length
;
for
(
let
i =
0
; i < L; i++) {
const
current = i;
let
neighbors =
this
.
matrix
[i].
map
(
(
m, index
) =>
{
index !== i &&
m ===
1
return
index;
return
null
;
neighbors = neighbors.
filter
(
n
=>
n !==
null
);
const
neighborsString = neighbors.
join
(
' '
);
console
.
log
(
`节点
${current}
, 相邻节点
${neighborsString}
`
);
图的广度优先遍历(BFS)
* 无向图
class
Graph
{
bfs (node) {
if
(node >=
0
&& node <
this
.
matrix
.
length
) {
const
result = [];
const
hash = {};
const
queue = [];
for
(
let
i =
0
; i <
this
.
matrix
.
length
; i++) {
hash[i] =
false
;
hash[node] =
true
;
result.
push
(node);
queue.
push
(node);
while
(queue.
length
>
0
) {
let
q = queue.
shift
();
let
list =
this
.
matrix
[q];
for
(
let
i =
0
; i < list.
length
; i++) {
list[i] ===
1
&&
!hash[i]
result.
push
(i);
hash[i] =
true
;
queue.
push
(i);
return
result;
return
-
1
;
dfs (node) {
if
(node >=
0
&& node <
this
.
matrix
.
length
) {
图的深度优先遍历(DFS)
* 无向图
class
Graph
{
dfs (node) {
if
(node >=
0
&& node <
this
.
matrix
.
length
) {
const
result = [];
const
hash = {};
for
(
let
i =
0
; i <
this
.
matrix
.
length
; i++) {
hash[i] =
false
;
hash[node] =
true
;
result.
push
(node);
const
DFS
= (
node
) => {
let
list =
this
.
matrix
[node];
for
(
let
i =
0
; i < list.
length
; i++) {
list[i] ===
1
&&
!hash[i]
result.
push
(i);
hash[i] =
true
;
DFS
(i);
DFS
(node);
return
result;
return
-
1
;
实现有向图(oriented graph)
领接表实现有向图
* 有向图
class
Graph
{
constructor
() {
this
.
adjacencyList
=
new
Map
();
addNode (node) {
if
(!
this
.
adjacencyList
.
has
(node)) {
this
.
adjacencyList
.
set
(node, []);
}
else
{
throw
new
Error
(
'节点已存在'
)
addEdge (to,
from
) {
this
.
adjacencyList
.
has
(to) &&
this
.
adjacencyList
.
has
(
from
)
let
toAdjacent =
this
.
adjacencyList
.
get
(to)
toAdjacent = [...
new
Set
([...toAdjacent,
from
])];
this
.
adjacencyList
.
set
(to, toAdjacent);
print () {
const
nodes =
this
.
adjacencyList
.
keys
();
for
(
let
node
of
nodes) {
const
neighbors =
this
.
adjacencyList
.
get
(node);
const
neighborsString = neighbors.
join
(
' '
);
console
.
log
(
`节点
${node}
, 相邻节点
${neighborsString}
`
);
领接矩阵实现有向图
* 有向图
class
Graph
{
constructor
() {
this
.
matrix
= [];
addNode () {
this
.
matrix
.
push
([]);
const
L =
this
.
matrix
.
length
;
for
(
let
i =
0
; i < L; i++) {
let
start =
this
.
matrix
[i].
length
;
while
(start < L) {
this
.
matrix
[i][start] =
0
;
start +=
1
addEdge (to,
from
) {
(to <
this
.
matrix
.
length
&& to >=
0
) &&
(
from
<
this
.
matrix
.
length
&&
from
>=
0
)
this
.
matrix
[to][
from
] =
1
;
print () {
const
L =
this
.
matrix
.
length
;
for
(
let
i =
0
; i < L; i++) {
const
current = i;
let
neighbors =
this
.
matrix
[i].
map
(
(
m, index
) =>
{
index !== i &&
m ===
1
return
index;
return
null
;
neighbors = neighbors.
filter
(
n
=>
n !==
null
);
const
neighborsString = neighbors.
join
(
' '
);
console
.
log
(
`节点
${current}
, 相邻节点
${neighborsString}
`
);
实现加权图(weighted-graph)
边具有权重的图
领接表实现加权图
使用数组存储每一个节点,数组的长度就是节点的数量。而数组的每一位则存储着,第
i
个节点相邻的节点列表, 以及每一个相领节点到当前节点的权重。
class
Graph
{
constructor
() {
this
.
adjacencyList
=
new
Map
();
addNode (node) {
if
(!
this
.
adjacencyList
.
has
(node)) {
this
.
adjacencyList
.
set
(node, []);
}
else
{
throw
new
Error
(
'节点已存在'
)
* 添加边
* to 节点1
* form 节点2
* weight 权重
addEdge (to,
from
, weight) {
this
.
adjacencyList
.
has
(to) &&
this
.
adjacencyList
.
has
(
from
) &&
typeof
weight ===
'number'
let
toAdjacent =
this
.
adjacencyList
.
get
(to);
let
fromAdjacent =
this
.
adjacencyList
.
get
(
from
);
toAdjacent = [...toAdjacent, [
from
, weight]];
fromAdjacent = [...fromAdjacent, [to, weight]];
this
.
adjacencyList
.
set
(to, toAdjacent);
this
.
adjacencyList
.
set
(
from
, fromAdjacent);
领接矩阵实现加权图
使用一个大小等于L * L的二维数组表示,L是节点的数量。Matrix[i][j], 表示节点 i 到 j边的权重值(0 ~ ∞),'*'表示没有边。
class Graph {
constructor () {
this.matrix = [];
addNode () {
this.matrix.push([]);
const L = this.matrix.length;
for (let i = 0; i < L; i++) {
let start = this.matrix[i].length;
while (start < L) {
this.matrix[i][start] = '*';
start += 1
* to 端点1
* from 端点2
* weight 端点1和端点2的权重
addEdge (to, from, weight) {
(to < this.matrix.length && to >= 0) &&
(from < this.matrix.length && from >= 0) &&
typeof weight === 'number'
this.matrix[to][from] = weight;
this.matrix[from][to] = weight;
最短路径问题
对于非加权图的最短路径问题,使用BFS(广度优先遍历)即可。
* 无向图中,查找某一个顶点,到其他顶点的最短路径
* graph 图
* node 起始的顶点
* 无权重的图,边的距离默认为1
const shortestPath = (graph, node) => {
graph &&
graph.adjacencyList &&
graph.adjacencyList.has(node)
const hash = {};
const queue = [];
const nodes = graph.adjacencyList.keys();
for (let node of nodes) {
hash[node] = false;
hash[node] = 0;
queue.push(node);
while (queue.length > 0) {
let q = queue.shift();
let list = graph.adjacencyList.get(q);
for (let i = 0; i < list.length; i++) {
let temp = list[i]
if (hash[temp] !== false && hash[temp] > hash[q] + 1) {
hash[temp] = hash[q] + 1;
if (hash[temp] === false) {
hash[temp] = hash[q] + 1;
queue.push(temp)
return hash;
return -1;
加权图的最短路径问题
Dijkstra
迪克斯特拉算法,是一种用于在图中查找节点之间最短路径的算法。由荷兰科学家,埃格斯·迪克斯特拉(1930年5月11日~2002年8月6日)在1956年提出。
首先先构建加权图
const graph = new Graph();
graph.addNode('start')
graph.addNode('A')
graph.addNode('B')
graph.addNode('C')
graph.addNode('D')
graph.addNode('finish')
graph.addEdge('start', 'A', 5)
graph.addEdge('start', 'B', 2)
graph.addEdge('A', 'B', 8)
graph.addEdge('A', 'C', 4)
graph.addEdge('A', 'D', 2)
graph.addEdge('B', 'D', 7)
graph.addEdge('C', 'D', 6)
graph.addEdge('C', 'finish', 3)
graph.addEdge('D', 'finish', 1)
* Dijkstra 算法
* @param graph 图
* @param startNode 开始的节点
* @param endNode 结束的节点
const Dijkstra = (graph, startNode, endNode) => {
graph.adjacencyList.has(startNode) &&
graph.adjacencyList.has(endNode) &&
endNode !== startNode
const queue = new Queue();
const path = [];
const timeHash = {};
const backHash = {};
const nodes = graph.adjacencyList.keys();
for (let node of nodes) {
timeHash[node] = Number.POSITIVE_INFINITY
timeHash[startNode] = 0;
queue.enqueue([startNode, 0]);
while (!queue.isEmpty()) {
const [currentNode] = queue.dequeue();
const list = graph.adjacencyList.get(currentNode);
for (let i = 0; i < list.length; i++) {
const [nextNode, nextNodeWeight] = list[i];
let time = timeHash[currentNode] + nextNodeWeight;
if (time < timeHash[nextNode]) {
timeHash[nextNode] = time;
backHash[nextNode] = currentNode;
queue.enqueue([nextNode, time]);
let lastNode = endNode
while (startNode !== lastNode) {
path.unshift(lastNode)
lastNode = backHash[lastNode];
path.unshift(startNode);
return `最短路径: ${path.join(' --> ')}, 所花费的时间: ${timeHash[endNode]}`
return -1
Dijkstra(graph, 'start', 'finish')
A Walkthrough of Dijkstra’s Algorithm (in JavaScript!)
Dijkstra's algorithm
What is a graph
Implementation of Graph in JavaScript