1 | import { LinkList } from "../linklist/LinkList";
|
2 | import { GraphEdge } from "./GraphEdge";
|
3 | import { GraphVertex } from "./GraphVertex";
|
4 |
|
5 | export 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 |
|
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 |
|
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 |
|
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 |
|
111 | for (const key in this.vertices) {
|
112 | keyIndexs[key] = index;
|
113 | matrix[index][index] = 0;
|
114 | index ++;
|
115 | }
|
116 |
|
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 | }
|