树(父子关系的节点集合)
二叉树(最多只有两个子节点)
数组(随机访问,顺序存储)
字典Map (键值对)
交通网络
通信网络
class Graph {
constructor(isDirected = false) {
this.isDirected = isDirected;
this.vertices = []; //顶点列表
this.adjList = new Map(); //顶点表示键,邻接顶点列表表示值
}
}
addVertex(v) {
if (!this.vertices.includes(v)) {
this.vertices.push(v);
//将新加顶点的邻接顶点列表初始为空数组
this.adjList.set(v, []);
}
}
addEdge(a, b) {
if (!this.adjList.get(a)) {
this.addVertex(a);
}
if (!this.adjList.get(b)) {
this.addVertex(b);
}
this.adjList.get(a).push(b);
if (this.isDirected !== true) {
this.adjList.get(b).push(a);
}
}
getVertices() {
return this.vertices;
}
getAdjList() {
return this.adjList;
}
toString() {
let s = '';
for (let i = 0; i < this.vertices.length; i++) {
s += `${this.vertices[i]} -> `;
const neighbors = this.adjList.get(this.vertices[i]);
for (let j = 0; j < neighbors.length; j++) {
s += `${neighbors[j]} `;
}
s += '\n';
}
return s;
}
const graph = new Graph();
const myVertices = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'];
for (let i = 0; i < myVertices.length; i++) {
graph.addVertex(myVertices[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());
广度优先搜索 | 队列 | 将顶点存入队列,最先入队列的顶点先被探索 |
深度优先搜索 | 栈 | 将顶点存入栈,顶点是沿着路径被探索的,存在新的相邻顶点就去访问 |
const Colors = {
WHITE: 0,
GREY: 1,
BLACK: 2
};
const initializeColor = vertices => {
const color = {};
for (let i = 0; i < vertices.length; i++) {
color[vertices[i]] = Colors.WHITE;
}
return color;
};
const breadthFirstSearch = (graph, startVertex, callback) => {
const vertices = graph.getVertices();
const adjList = graph.getAdjList();
const color = initializeColor(vertices);
const queue = new Queue();
queue.enqueue(startVertex);
while (!queue.isEmpty()) {
const u = queue.dequeue();
const neighbors = adjList.get(u);
color[u] = Colors.GREY;
for (let i = 0; i < neighbors.length; i++){
const w = neighbors[i];
if(color[w] === Colors.WHITE) {
color[w] = Colors.GREY;
queue.enqueue(w);
}
}
color[u] = Colors.BLACK;
if (callback) {
callback(u);
}
}
}
const printVertex = (value) => console.log('Visited vertex: ' + value);
breadthFirstSearch(graph, myVertices[0], printVertex);
const depthFirstSearch = (graph, callback) => {
const vertices = graph.getVertices();
const adjList = graph.getAdjList();
const color = initializeColor(vertices);
for (let i = 0; i < vertices.length; i++) { // {2}
if (color[vertices[i]] === Colors.WHITE) { // {3}
depthFirstSearchVisit(vertices[i], color, adjList, callback); // {4}
}
}
};
const depthFirstSearchVisit = (u, color, adjList, callback) => {
color[u] = Colors.GREY; // {5}
if (callback) { // {6}
callback(u);
}
const neighbors = adjList.get(u); // {7}
for (let i = 0; i < neighbors.length; i++) { // {8}
const w = neighbors[i]; // {9}
if (color[w] === Colors.WHITE) { // {10}
depthFirstSearchVisit(w, color, adjList, callback); // {11}
}
}
color[u] = Colors.BLACK; // {12}
};
depthFirstSearch(graph, printVertex);
用邻接表创建下图,并分别用BFS和DFS两种方法遍历下图。
var graph = [
[0, 2, 4, 0, 0, 0],
[2, 0, 2, 4, 2, 0],
[4, 2, 0, 0, 3, 0],
[0, 4, 0, 0, 3, 2],
[0, 2, 3, 3, 0, 2],
[0, 0, 0, 2, 2, 0]];
const INF = Number.MAX_SAFE_INTEGER;
const kruskal = graph => {
const { length } = graph; //邻接矩阵
const parent = [];//生成树,父子结点,边
let ne = 0;
let a; let b; let u; let v;
const cost = initializeCost(graph); //复制邻接矩阵
while (ne < length - 1) { // 找n-1条边
//在cost矩阵中找权值最小的边
for (let i = 0, min = INF; i < length; i++) {
for (let j = 0; j < length; j++) {
if (cost[i][j] < min) {
min = cost[i][j];
a = u = i;
b = v = j;
}
}
}
//判断最小权值边的两个顶点是否属于同一棵树,有相同的根结点
//找u的根结点
u = find(u, parent);
//找v的根结点
v = find(v, parent);
//如果u,v根结点不相同,则该边加入最小生成树
if (union(u, v, parent)) {
ne++;
}
cost[a][b] = cost[b][a] = INF; //去除该边
}
return parent;
}
//复制矩阵
const initializeCost = (graph) => {
let ret = [];
for(let i = 0; i < graph.length; i++){
ret[i] = [];
for(let j = 0; j < graph[i].length; j++){
ret[i][j] = graph[i][j];
}
}
return ret;
}
//找根结点
const find = (i, parent) => {
while (parent[i]) {
i = parent[i];
}
return i;
};
//判断两个顶点是否属于同一棵树
const union = (i, j, parent) => {
if (i !== j) {
parent[j] = i; //i作为j的父结点
return true;
}
return false;
};
const INF = Number.MAX_SAFE_INTEGER;
const prim = graph => {
const parent = []; //每个顶点的父结点
const key = []; //最短边的权值
const visited = []; //访问过顶点设置为true
const { length } = graph; //顶点数
//初始化
for (let i = 0; i < length; i++) {
key[i] = INF;
visited[i] = false;
}
//开始顶点
key[0] = 0;
parent[0] = -1;
//找所有的顶点
for (let i = 0; i < length; i++) {
//找到key最小结点索引
const u = minKey(key, visited);
visited[u] = true;
for (let v = 0; v < length; v++) {
if (graph[u][v] && !visited[v] && graph[u][v] < key[v]) { // {6}
//设置v的父结点
parent[v] = u;
//更新v的权值
key[v] = graph[u][v];
}
}
}
return parent;
};
//找key且对应的visited为flase的最小值索引
const minKey = (key, visited) => {
let min = INF;
let minIndex = -1;
for (let v = 0; v < key.length; v++) {
if (visited[v] === false && key[v] <= min) {
min = key[v];
minIndex = v;
}
}
return minIndex;
};
var graph = [
[0, 2, 4, 0, 0, 0],
[0, 0, 2, 4, 2, 0],
[0, 0, 0, 0, 3, 0],
[0, 0, 0, 0, 0, 2],
[0, 0, 0, 3, 0, 2],
[0, 0, 0, 0, 0, 0]];
$$ dist[j] = Min\{dist[i]\} $$ dist[j] + arcs[j][k] < disk[k]时 $$ dist[k] = dist[j] + arcs[j][k] $$
const INF = Number.MAX_SAFE_INTEGER;
const dijkstra = (graph, src) => {
const dist = []; //dist[i]存储src到i的最短路径的长度
const visited = [];//设置访问过顶点为true
const { length } = graph;//顶点数
//初始化
for (let i = 0; i < length; i++) {
dist[i] = INF;
visited[i] = false;
}
//源点
dist[src] = 0;
for (let i = 0; i < length - 1; i++) {
const u = minDistance(dist, visited);
visited[u] = true;
for (let v = 0; v < length; v++) {
if (!visited[v] &&
graph[u][v] !== 0 &&
dist[u] !== INF &&
dist[u] + graph[u][v] < dist[v]) {
dist[v] = dist[u] + graph[u][v];
}
}
}
return dist;
};
const minDistance = (dist, visited) => {
let min = INF;
let minIndex = -1;
for (let v = 0; v < dist.length; v++) {
if (visited[v] === false && dist[v] <= min) {
min = dist[v];
minIndex = v;
}
}
return minIndex;
};
const floyd = graph => {
const dist = [];
const { length } = graph;
for (let i = 0; i < length; i++) {
dist[i] = [];
for (let j = 0; j < length; j++) {
if (i === j) {
dist[i][j] = 0;
} else if ((graph[i][j] === 0) && (i !== j)) {
dist[i][j] = Infinity;
} else {
dist[i][j] = graph[i][j];
}
}
}
for (let k = 0; k < length; k++) {
for (let i = 0; i < length; i++) {
for (let j = 0; j < length; j++) {
if (dist[i][k] + dist[k][j] < dist[i][j]) { // {6}
dist[i][j] = dist[i][k] + dist[k][j]; // {7}
}
}
}
}
return dist;
};