class Vertex {
firstEdge: string = ''
data: any
outNum: number = 0
inNum: number = 0
constructor(data: any) {
this.data = data;
}
}
class Edge {
data: any
nextEdge: any
weight: number
constructor(data: any, weight: number = 0) {
this.data = data;
this.weight = weight;
}
}
class Graph {
eNum: number = 0
adj: Array<any> = []
isDirect: boolean
constructor(isDirect: boolean) {
this.isDirect = isDirect;
}
initVertex(verArr: Array<string>) {
for (let i = 0; i < verArr.length; i++) {
let newVer = new Vertex(verArr[i]);
this.adj[i] = newVer;
}
}
_find(x: string) {
let pos = -1;
for (let i = 0; i < this.adj.length; i++) {
if (x === this.adj[i].data) {
pos = i;
}
}
return pos;
}
insertVertex(x: string) {
let newVer = new Vertex(x);
this.adj.push(newVer);
}
allNeightbors(x: string) {
let pos = this._find(x);
let curEdge = this.adj[pos].firstEdge;
let arr = [];
while (curEdge) {
arr.push(curEdge.data);
curEdge = curEdge.nextEdge;
}
return arr;
}
addEdge(x: string, y: string, w: number = 0) {
let posX = this._find(x);
let posY = this._find(y);
let newEdgeX = new Edge(x, w);
let newEdgeY = new Edge(y, w);
if (!this.isDirect) {
if (!this.hasEdge(x, y) && !this.hasEdge(y, x)) {
if (posX > -1) {
let curEdge = this.adj[posX].firstEdge;
if (!curEdge) {
this.adj[posX].firstEdge = newEdgeY;
} else {
let len = this.adj[posX].outNum - 1;
while (len--) {
curEdge = curEdge.nextEdge;
}
curEdge.nextEdge = newEdgeY;
}
this.adj[posX].outNum++;
}
if (posY > -1) {
let curEdge = this.adj[posY].firstEdge;
if (!curEdge) {
this.adj[posY].firstEdge = newEdgeX;
this.adj[posY].outNum++;
} else {
let len = this.adj[posY].outNum - 1;
while (len--) {
curEdge = curEdge.nextEdge;
}
curEdge.nextEdge = newEdgeX;
this.adj[posY].outNum++;
}
}
this.eNum++;
}
} else {
if (!this.hasEdge(x, y)) {
if (posX > -1) {
let curEdge = this.adj[posX].firstEdge;
if (!curEdge) {
this.adj[posX].firstEdge = newEdgeY;
} else {
let len = this.adj[posX].outNum - 1;
while (len--) {
curEdge = curEdge.nextEdge;
}
curEdge.nextEdge = newEdgeY;
}
this.adj[posX].outNum++;
this.eNum++;
}
if (posY > -1) {
let curVer = this.adj[posY];
curVer.inNum++;
}
}
}
}
removeEdge(x: string, y: string) {
let posX = this._find(x);
let posY = this._find(y);
if (!this.isDirect) {
if (this.hasEdge(x, y) && this.hasEdge(y, x)) {
if (posX > -1) {
let curEdge = this.adj[posX].firstEdge;
let preEdge = null;
if (curEdge.data === y) {
this.adj[posX].firstEdge = curEdge.nextEdge;
this.adj[posX].outNum--;
curEdge.data = 0;
curEdge = null;
}
while (curEdge) {
preEdge = curEdge;
curEdge = curEdge.nextEdge;
if (curEdge && curEdge.data === y) {
preEdge.nextEdge = curEdge.nextEdge;
this.adj[posX].outNum--;
curEdge.data = 0;
curEdge = null;
}
}
}
if (posY > -1) {
let curEdge = this.adj[posY].firstEdge;
let preEdge = null;
if (curEdge.data === x) {
this.adj[posY].firstEdge = curEdge.nextEdge;
this.adj[posY].outNum--;
curEdge.data = 0;
curEdge = null;
}
while (curEdge) {
preEdge = curEdge;
curEdge = curEdge.nextEdge;
if (curEdge && curEdge.data === x) {
preEdge.nextEdge = curEdge.nextEdge;
this.adj[posY].outNum--;
curEdge.data = 0;
curEdge = null;
}
}
}
this.eNum--;
}
} else {
if (this.hasEdge(x, y)) {
if (posX > -1) {
let curEdge = this.adj[posX].firstEdge;
let preEdge = null;
if (curEdge.data === y) {
this.adj[posX].firstEdge = curEdge.nextEdge;
curEdge.data = 0;
this.adj[posX].outNum--;
curEdge = null;
}
while (curEdge) {
preEdge = curEdge;
curEdge = curEdge.nextEdge;
if (curEdge.data == y) {
preEdge.nextEdge = curEdge.nextEdge;
curEdge.data = 0;
this.adj[posX].outNum--;
curEdge = null;
}
}
if (this.adj[posY]) {
this.adj[posY].inNum--;
}
}
this.eNum--;
}
}
}
deleteVertex(x: string) {
let pos = this._find(x);
if (pos > -1) {
let curEdge = this.adj[pos].firstEdge;
while (curEdge) {
this.removeEdge(x, curEdge.data);
curEdge = curEdge.nextEdge;
}
for (let i = 0; i < this.adj.length; i++) {
let temVer = this.adj[i].firstEdge;
while (temVer) {
if (temVer.data === x) {
this.removeEdge(this.adj[i].data, temVer.data);
}
temVer = temVer.nextEdge;
}
}
this.adj.splice(pos, 1);
}
}
hasEdge(x: string, y: string) {
let pos = this._find(x);
if (pos > -1) {
let curEdge = this.adj[pos].firstEdge;
while (curEdge) {
if (curEdge.data == y) return true;
curEdge = curEdge.nextEdge;
}
return false;
}
}
getAllEdge(): Array<any> {
let arr = new Array(this.adj.length).fill(0).map(item => new Array(this.adj.length).fill(0));
let j = 0;
for (let i = 0; i < this.adj.length; i++) {
let curEdge = this.adj[i].firstEdge;
while (curEdge) {
arr[j++] = curEdge;
curEdge = curEdge.nextEdge;
}
}
return arr;
}
getEdgeWeight(x: string, y: string) {
let pos = this._find(x);
if (pos > -1) {
let curEdge = this.adj[pos].firstEdge;
while (curEdge) {
if (curEdge.data === y) {
return curEdge.weight;
}
curEdge = curEdge.nextEdge;
}
return 0;
}
}
getMaxEdgeWeight() {
let i = 0;
let curVer = this.adj[i];
let max = 0;
while (curVer) {
let curEdge = curVer.firstEdge;
while (curEdge) {
if (curEdge.weight > max) {
max = curEdge.weight;
}
curEdge = curEdge.next;
}
curVer = this.adj[++i];
}
return max;
}
getMinEdgeWeight() {
let i = 0;
let curVer = this.adj[i];
let min = Number.MAX_SAFE_INTEGER;
while (curVer) {
let curEdge = curVer.firstEdge;
while (curEdge) {
if (curEdge.weight < min) {
min = curEdge.weight;
}
curEdge = curEdge.next;
}
curVer = this.adj[++i];
}
return min;
}
setEdgeWeight(x: string, y: string, w: number) {
}
BFSTraverse(x: string = this.adj[0].data) {
let len = this.adj.length;
let visited = new Array(len).fill(false);
let result = '';
result = this._BFS(x, visited);
for (let i = 0; i < len; i++) {
if (!visited[i]) {
result += `&${this._BFS(this.adj[i].data, visited)}`;
}
}
return result;
}
_BFS(x: string, visited: Array<any>) {
let pos: any = this._find(x);
let result = '';
let queue = [];
if (pos > -1) {
result += `${x}`;
queue.push(pos);
visited[pos] = true;
while (queue.length) {
pos = queue.shift();
let curVer = this.adj[pos].firstEdge;
while (curVer) {
pos = this._find(curVer.data);
if (!visited[pos]) {
visited[pos] = true;
result += `->${this.adj[pos].data}`;
queue.push(pos);
}
curVer = curVer.nextEdge;
}
}
}
return result;
}
DFSTraverse(x: string) {
let len = this.adj.length;
let visited = new Array(len).fill(false);
let result = '';
result = this._DFS(x, visited);
for (let i = 0; i < this.adj.length; i++) {
if (!visited[i]) {
result += this._DFS(this.adj[i].data, visited)
}
}
return result;
}
_DFS(x: string, visited: Array<any>) {
let result = '';
let stack = [];
let pos = this._find(x);
let curVer = this.adj[pos];
if (pos > -1) {
stack.push(curVer);
result += `${x}`;
visited[pos] = true;
while (stack.length) {
curVer = stack[stack.length - 1]
pos = this._find(curVer.data);
curVer = this.adj[pos].firstEdge;
while (curVer) {
pos = this._find(curVer.data);
if (visited[pos]) {
curVer = curVer.nextEdge;
} else {
stack.push(curVer);
result += `->${curVer.data}`;
visited[pos] = true;
break;
}
}
if (!curVer) stack.pop();
}
}
return result;
}
isConnected(x = this.adj[0].data) {
let len = this.adj.length;
let visited = new Array(len).fill(0);
this._BFS(x, visited);
for (let i = 0; i < len; i++) {
if (!visited[i]) {
return false;
}
}
return true;
}
getPrimMSTree() {
if (!this.isConnected) {
return false;
}
let V = this.adj;
let Vt = [V[0]];
let VVt = V.filter(item => Vt.indexOf(item) === -1);
let MSTree = new Graph(this.isDirect);
V.forEach(x => MSTree.insertVertex(x.data));
while (Vt.length != V.length) {
let mVt = null;
let mVVt = null;
let minW = Number.MAX_SAFE_INTEGER;
let i = Vt.length - 1;
for (let j = 0; j < VVt.length; j++) {
let weight = this.getEdgeWeight(Vt[i].data, VVt[j].data);
if (weight && minW > weight) {
minW = weight;
mVt = Vt[i];
mVVt = VVt[j];
}
}
Vt.push(mVVt);
MSTree.addEdge(mVt.data, mVVt.data, minW);
VVt = V.filter(x => Vt.indexOf(x) === -1);
}
return MSTree;
}
getKruskalMST() {
if (!this.isConnected()) {
return;
}
let V = this.adj;
let numS = V.length;
let E = this.getAllEdge();
let mEdge: any = null;
let MSTree = new Graph(this.isDirect);
V.forEach(x => MSTree.insertVertex(x.data));
while (numS > 1) {
let mWeight = Number.MAX_SAFE_INTEGER;
let j: any = 0;
for (let i = 0; i < E.length; i++) {
if (E[i].weight < mWeight) {
mEdge = E[i];
j = i + 1;
mWeight = mEdge.weight;
}
}
j = j / this.adj.length;
j = parseInt(j);
let result = MSTree.BFSTraverse(this.adj[j].data);
result = result.split('&')[0];
let pos = result.indexOf(mEdge.data);
if (pos === -1) {
MSTree.addEdge(this.adj[j].data, mEdge.data, mEdge.weight);
numS--;
}
E = E.filter(x => x !== mEdge);
}
return MSTree;
}
getSumOfWeight() {
if (!this.isConnected()) return;
let sum = 0;
let vertex = this.adj;
if (!this.isDirect) {
for (let i = 0; i < vertex.length - 1; i++) {
for (let j = i; j < vertex.length; j++) {
let weight = this.getEdgeWeight(vertex[i].data, vertex[j].data);
if (weight) sum += weight;
}
}
} else {
for (let i = 0; i < vertex.length; i++) {
for (let j = 0; j < vertex.length; j++) {
let weight = this.getEdgeWeight(vertex[i].data, vertex[j].data);
if (weight) sum += weight;
}
}
}
return sum;
}
getShortestPath(x: string) {
if (!this.isDirect
|| this.getMinEdgeWeight() < 0
|| this._find(x) === -1
|| !this.isConnected(x)) { return -1; }
let MAX = Number.MAX_SAFE_INTEGER;
let len = this.adj.length;
let dist = [];
let path = [];
let vers = [];
let exts = [x];
for (let i = 0; i < len; i++) {
vers[i] = this.adj[i].data;
dist[i] = this.getEdgeWeight(x, vers[i]) || MAX;
if (dist[i] !== MAX) {
path[i] = `${x}->${vers[i]}`;
} else {
path[i] = '';
}
}
let rem = vers.filter(x => exts.indexOf(x) === -1);
let n = 1;
while (n < len) {
let min = MAX;
let idx = -1;
for (let i = 0; i < len; i++) {
if (min > dist[i]) {
min = dist[i];
idx = i;
}
}
let Vj = vers[idx];
dist[idx] = MAX;
exts.push(Vj);
rem = vers.filter(x => exts.indexOf(x) === -1);
console.log(path[idx]);
for (let i = 0; i < rem.length; i++) {
let w = this.getEdgeWeight(Vj, rem[i]) || MAX;
let k = vers.indexOf(rem[i]);
if (w + min < dist[k]) {
dist[k] = w + min;
path[k] = `${path[idx]}->${rem[i]}`;
}
}
n++;
}
}
getTopoSort() {
if (this.isDirect) {
let adj = JSON.parse(JSON.stringify(this.adj));
let stack: any = [];
let result = '';
let count = 0;
for (let i = 0; i < adj.length; i++) {
if (adj[i].inNum === 0) {
stack.push(i);
}
}
while (stack.length) {
let gettop = stack.pop();
result+=gettop+'->';
count++;
for (let e = adj[gettop].firstEdge; e; e = e.nextEdge) {
let k = this._find(e.data);
if(!(adj[k].inNum -= 1)) {
stack.push(k);
}
}
}
if(count != adj.length) {
return false;
}
return result;
}
}
topologicalSort() {
if (!this.isDirect) {
return;
}
let top = 0, count = 0;
let adj = JSON.parse(JSON.stringify(this.adj));
let gettop: any, k;
let result = '';
let stack = [];
let stack2 = [];
let etv = new Array(adj.length).fill(0);
for (let i = 0; i < adj.length; i++) {
if (this.adj[i].inNum == 0) {
stack.push(i);
}
}
while (stack.length) {
gettop = stack.pop();
result += adj[gettop].data + '-> ';
count++;
stack2.push(gettop);
for (let e = adj[gettop].firstEdge; e; e = e.nextEdge) {
k = this._find(e.data);
if (!(adj[k].inNum -= 1)) {
stack.push(k);
}
if (etv[gettop] + e.weight > etv[k]) {
etv[k] = etv[gettop] + e.weight;
}
}
}
if (count < adj.length) {
console.info('发生错误,有环路存在');
return false;
}
return {
etv: etv,
stack: stack2
};
}
getCriticalPath() {
let topological:any = this.topologicalSort();
let etv = topological.etv;
let stack = topological.stack;
let adj = JSON.parse(JSON.stringify(this.adj));
console.info('可计算的最早发生时间数组etv:' + etv);
console.info('拓扑序列:' + stack);
let gettop, k;
let ltv = new Array();
for (let i = 0; i < this.adj.length; i++) {
ltv[i] = etv[this.adj.length - 1];
}
while (stack.length) {
gettop = stack.pop();
for (let e = adj[gettop].firstEdge; e; e = e.nextEdge) {
k = this._find(e.data);
if (ltv[k] - e.weight < ltv[gettop]) {
ltv[gettop] = ltv[k] - e.weight;
}
}
}
for (let j = 0; j <adj.length; j++) {
for (let e = adj[j].firstEdge; e; e = e.nextEdge) {
k = this._find(e.data);
if (etv[j] == ltv[k] - e.weight) {
console.info(adj[j].data + '到' + adj[k].data + '(' + e.weight + ')');
}
}
}
}
}
let arr2 = ['v0', 'v1', 'v2', 'v3', 'v4', 'v5', 'v6', 'v7', 'v8', 'v9'];
let myGraph = new Graph(true);
myGraph.initVertex(arr2);
myGraph.addEdge('v0', 'v2', 4);
myGraph.addEdge('v0', 'v1', 3);
myGraph.addEdge('v1', 'v4', 6);
myGraph.addEdge('v1', 'v3', 5);
myGraph.addEdge('v2', 'v5', 7);
myGraph.addEdge('v2', 'v3', 8);
myGraph.addEdge('v3', 'v4', 3);
myGraph.addEdge('v4', 'v7', 4);
myGraph.addEdge('v4', 'v6', 9);
myGraph.addEdge('v5', 'v7', 6);
myGraph.addEdge('v6', 'v9', 2);
myGraph.addEdge('v7', 'v8', 5);
myGraph.addEdge('v8', 'v9', 3);
myGraph.getCriticalPath();
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了