1 | import { Dijkstra } from './dijkstra.utils';
|
2 | export class GraphUtils {
|
3 | |
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 | static toGraphMatrix(nodes: NodeBase<any>[], edges: EdgeBase<any>[], directed = false, distanceProp = "distance"): number[][] {
|
12 | let m = GraphUtils.getMatrix(nodes.length);
|
13 | let nodeMap = new Object();
|
14 | let idx = 0;
|
15 | for (let vertex of nodes) {
|
16 | nodeMap[vertex.id] = idx;
|
17 | idx++;
|
18 | }
|
19 | for (let edge of edges) {
|
20 | let distance = edge[distanceProp];
|
21 | if (!distance) {
|
22 | distance = 1;
|
23 | }
|
24 | m[nodeMap[edge.source.id]][nodeMap[edge.target.id]] = distance;
|
25 | if (!directed) {
|
26 | m[nodeMap[edge.target.id]][nodeMap[edge.source.id]] = distance;
|
27 | }
|
28 | }
|
29 | return m;
|
30 | }
|
31 | private static getMatrix(length: number): number[][] {
|
32 | let m = new Array<number[]>(length);
|
33 | for (let idx = 0; idx < m.length; idx++) {
|
34 | m[idx] = new Array<number>(length);
|
35 | }
|
36 | return m;
|
37 | }
|
38 | |
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 | static getShortedPathAll(nodes: NodeBase<any>[], edges: EdgeBase<any>[], start: NodeBase<any>, directed = false): NodeBase<any>[][] {
|
46 | let graph = GraphUtils.toGraphMatrix(nodes, edges, directed);
|
47 | let pos: number = GraphUtils.getNodePosition(nodes, start);
|
48 | let paths = GraphUtils.getMatrix(nodes.length);
|
49 | let dists = Dijkstra.getShortedPathAll(graph, pos, paths);
|
50 | let pathNodeMatrix = new Array();
|
51 | for (let path of paths) {
|
52 | let pathNodes = new Array<NodeBase<any>>();
|
53 | for (let n of path) {
|
54 | if (n == undefined) {
|
55 | break;
|
56 | }
|
57 | pathNodes.push(nodes[n]);
|
58 | }
|
59 | pathNodeMatrix.push(pathNodes);
|
60 | }
|
61 | return pathNodeMatrix;
|
62 | }
|
63 | |
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 | static getShortedPath(nodes: NodeBase<any>[], edges: EdgeBase<any>[], start: NodeBase<any>, end: NodeBase<any>, directed = false): NodeBase<any>[] {
|
72 | let graph = GraphUtils.toGraphMatrix(nodes, edges, directed);
|
73 | let startPos: number = GraphUtils.getNodePosition(nodes, start);
|
74 | let endPos: number = GraphUtils.getNodePosition(nodes, end);
|
75 | let path = new Array<number>(nodes.length);
|
76 | let dist = Dijkstra.getShortedPath(graph, startPos, endPos, path);
|
77 | let pathNodes = new Array<NodeBase<any>>();
|
78 | for (let n of path) {
|
79 | if (!n) {
|
80 | break;
|
81 | }
|
82 | pathNodes.push(nodes[n]);
|
83 | }
|
84 | return pathNodes;
|
85 | }
|
86 |
|
87 | |
88 |
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 | static getConnectedNodes(nodes: NodeBase<any>[], edges: EdgeBase<any>[], start: NodeBase<any>, directed = false): NodeBase<any>[] {
|
95 | let graph = GraphUtils.toGraphMatrix(nodes, edges, directed);
|
96 | let pos: number = GraphUtils.getNodePosition(nodes, start);
|
97 | let m = GraphUtils.getMatrix(nodes.length);
|
98 | let nodeIdxs = GraphUtils.getConectedbyBfs(graph, pos);
|
99 | let cverts = [];
|
100 | for (let i of nodeIdxs) {
|
101 | cverts.push(nodes[i]);
|
102 | }
|
103 | graph = null;
|
104 | m = null;
|
105 | nodeIdxs = null;
|
106 | return cverts;
|
107 | }
|
108 | |
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 | static getNodePosition(nodes: NodeBase<any>[], v0: NodeBase<any>): number {
|
115 | for (let i = 0; i < nodes.length; i++) {
|
116 | if (nodes[i].id == v0.id) {
|
117 | return i;
|
118 | }
|
119 | }
|
120 | return undefined;
|
121 | }
|
122 | |
123 |
|
124 |
|
125 |
|
126 |
|
127 |
|
128 |
|
129 |
|
130 |
|
131 | public static isConnected(nodes: NodeBase<any>[], edges: EdgeBase<any>[], start: NodeBase<any>, end: NodeBase<any>, directed: boolean): boolean {
|
132 | let graph = GraphUtils.toGraphMatrix(nodes, edges, directed);
|
133 | let startPos: number = GraphUtils.getNodePosition(nodes, start);
|
134 | let endPos = GraphUtils.getNodePosition(nodes, end);
|
135 | return GraphUtils.isConectedbyBfs(graph, startPos, endPos);
|
136 |
|
137 | }
|
138 | static getConectedbyBfs(graph: number[][], start: number): number[] {
|
139 | let row = graph.length
|
140 | let queue = []
|
141 | let i = start
|
142 | let visited = {}
|
143 | let order = []
|
144 | queue.push(i)
|
145 | while (queue.length) {
|
146 | for (let j = 0; j < row; j++) {
|
147 | if (graph[i][j]) {
|
148 | if (!visited[j]) {
|
149 | queue.push(j)
|
150 | }
|
151 | }
|
152 | }
|
153 | queue.shift()
|
154 | visited[i] = true
|
155 | while (visited[queue[0]]) {
|
156 | queue.shift()
|
157 | }
|
158 | order.push(i)
|
159 | i = queue[0]
|
160 | }
|
161 | queue = null;
|
162 | visited = null;
|
163 | return order;
|
164 | }
|
165 | static isConectedbyBfs(arr: number[][], start: number, end: number): boolean {
|
166 | let row = arr.length;
|
167 | let queue = [];
|
168 | let i = start;
|
169 | let visited = {};
|
170 | let order = [];
|
171 | queue.push(i);
|
172 | while (queue.length) {
|
173 | for (let j = 0; j < row; j++) {
|
174 | if (arr[i][j]) {
|
175 | if (!visited[j]) {
|
176 | queue.push(j);
|
177 | }
|
178 | }
|
179 | }
|
180 | queue.shift();
|
181 | visited[i] = true;
|
182 | console.log("visit node:" + i);
|
183 | if (i == end) {
|
184 | return true;
|
185 | }
|
186 | while (visited[queue[0]]) {
|
187 | queue.shift();
|
188 | }
|
189 | order.push(i);
|
190 | i = queue[0];
|
191 | }
|
192 | queue = null;
|
193 | visited = null;
|
194 | order = null;
|
195 | return false;
|
196 | }
|
197 |
|
198 | |
199 |
|
200 |
|
201 |
|
202 |
|
203 |
|
204 |
|
205 |
|
206 |
|
207 | static toGraphData<N, E>(nodes: Array<N>, edges: Array<E>, idProp = "id", sourceIdProp = "sourceId", targetIdProp = "targetId"): GraphData<N, E> {
|
208 | let nodeMap = {};
|
209 | let graphData = new GraphData<N, E>();
|
210 | graphData.nodes = new Array<NodeBase<N>>(nodes.length);
|
211 | graphData.edges = new Array<EdgeBase<E>>(edges.length);
|
212 |
|
213 | for (let i = 0; i < nodes.length; i++) {
|
214 | let nd = nodes[i];
|
215 | let node = new NodeBase<any>();
|
216 | node.id = nd[idProp];
|
217 | node.data = nd;
|
218 | nodeMap[node.id] = node;
|
219 | graphData.nodes[i] = node;
|
220 | }
|
221 | for (let i = 0; i < edges.length; i++) {
|
222 | let ed = edges[i];
|
223 | let edge: EdgeBase<E> = new EdgeBase<E>();
|
224 | edge.source = nodeMap[ed[sourceIdProp]];
|
225 | edge.target = nodeMap[ed[targetIdProp]];
|
226 | edge.data = ed;
|
227 | graphData.edges[i] = edge;
|
228 | }
|
229 | nodeMap = null;
|
230 | return graphData;
|
231 | }
|
232 | }
|
233 |
|
234 |
|
235 |
|
236 | export class NodeBase<N> {
|
237 | |
238 |
|
239 |
|
240 | id: string;
|
241 | |
242 |
|
243 |
|
244 | data: N;
|
245 | }
|
246 |
|
247 |
|
248 |
|
249 | export class EdgeBase<E> {
|
250 | |
251 |
|
252 |
|
253 | source: NodeBase<any>;
|
254 | |
255 |
|
256 |
|
257 | target: NodeBase<any>;
|
258 | |
259 |
|
260 |
|
261 | distance = 1;
|
262 | |
263 |
|
264 |
|
265 | data: E;
|
266 | }
|
267 | export class GraphData<N, E> {
|
268 | nodes: NodeBase<N>[];
|
269 | edges: EdgeBase<E>[];
|
270 | } |
\ | No newline at end of file |