UNPKG

4.35 kBPlain TextView Raw
1import { LinkList } from "../linklist/LinkList";
2import { GraphEdge } from "./GraphEdge";
3import { GraphVertex } from "./GraphVertex";
4
5export class Graph<T = string>{
6 private vertices: {[index: string]: GraphVertex<T>};
7 private edges: {[index: string]: LinkList<GraphEdge<T>>};
8 constructor(private directed = true){
9 this.vertices = {};
10 this.edges = {};
11 }
12
13 public get Directed(){
14 return this.directed;
15 }
16
17 public addVertex(vertex: GraphVertex<T>){
18 this.vertices[vertex.Key] = vertex;
19 this.edges[vertex.Key] = vertex.getEdges();
20 return this;
21 }
22
23 public addEdgeByKey(start: string, end: string, weight?: number){
24 const startVertex = this.findVertex(start);
25 const endVertex = this.findVertex(end);
26 if (!startVertex || !endVertex){
27 throw new Error("vertex has not found");
28 }
29 return this.addEdge(startVertex, endVertex, weight);
30 }
31
32 public addEdge(start: GraphVertex<T>, end: GraphVertex<T>, weight?: number){
33 if (!start){
34 throw new Error("vertex is not empty");
35 }
36 if (this.directed){
37 start.addEdge(end, weight);
38 }else{
39 start.addUndirectedEdge(end, weight);
40 }
41 return this;
42 }
43
44 public deleteEdge(start: GraphVertex<T>, end: string){
45 if (!start){
46 throw new Error("vertex is not empty");
47 }
48 return start.deleteEdgeByKey(end, this.directed);
49 }
50
51 public deleteEdgeByKey(start: string, end: string){
52 const startVertex = this.findVertex(start);
53 if (startVertex){
54 return this.deleteEdge(startVertex, end);
55 }
56 return false;
57 }
58
59 public getVertexs(){
60 const arr: Array<GraphVertex<T>> = [];
61 // tslint:disable-next-line:forin
62 for (const key in this.vertices){
63 arr.push(this.vertices[key]);
64 }
65 return arr;
66 }
67
68 public getKeys(){
69 return Object.keys(this.vertices);
70 }
71
72 public getEdges(){
73 let arr: Array<GraphEdge<T>> = [];
74 // tslint:disable-next-line:forin
75 for (const key in this.edges){
76 arr = [...arr, ...this.edges[key].toArray().map(item => item.Value)];
77 }
78 return arr;
79 }
80
81 public findVertex(key: string){
82 return this.vertices[key];
83 }
84
85 public findEdge(key: string){
86 return this.edges[key];
87 }
88
89 public deleteVertex(key: string){
90 if (!(key in this.vertices)){
91 return false;
92 }
93 delete this.vertices[key];
94 delete this.edges[key];
95 // 有关联的边删除
96 // tslint:disable-next-line:forin
97 for (const tempKey in this.vertices){
98 const element = this.vertices[tempKey];
99 element.deleteEdgeByKey(key);
100 }
101 return true;
102 }
103
104 public toAdjacencyMatrix(){
105 const keys = this.getKeys();
106 const matrix: Array<Array<number>> = new Array(keys.length)
107 .fill(0).map(() => new Array(keys.length).fill(Infinity));
108 const keyIndexs: {[index: string]: number} = {};
109 let index = 0;
110 // tslint:disable-next-line:forin
111 for (const key in this.vertices) {
112 keyIndexs[key] = index;
113 matrix[index][index] = 0;
114 index ++;
115 }
116 // tslint:disable-next-line:forin
117 for (const key in this.vertices) {
118 const vertex = this.vertices[key];
119 const edges = vertex.getEdges().toArray();
120 for (const edgeNode of edges) {
121 const edge = edgeNode.Value;
122 matrix[keyIndexs[key]][keyIndexs[edge.EndVertex.Key]] = edge.Weight;
123 }
124 }
125 return {
126 matrix,
127 keyIndexs,
128 };
129 }
130
131 public clone(){
132 const vertices = this.getVertexs();
133 const edges = this.getEdges();
134 const graph = new Graph<T>(this.directed);
135 vertices.forEach(item => graph.addVertex(new GraphVertex(item.Node, item.Property)));
136 edges.forEach(item => {
137 const startVertex = graph.findVertex(item.StartVertex.Key);
138 const endVertex = graph.findVertex(item.EndVertex.Key);
139 graph.addEdge(startVertex, endVertex, item.Weight);
140 });
141 return graph;
142 }
143}