-
Notifications
You must be signed in to change notification settings - Fork 122
/
Copy pathAdjacencyListGraph.js
1245 lines (1010 loc) · 40.2 KB
/
AdjacencyListGraph.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* Create By Luke */
import Stack from '../Stack/index';
import Queue from '../Queue/Queue';
import { ChildSiblingTree } from '../BinaryTree/BinaryTree';
// 图的数组(邻接矩阵)存储表示
const DG = 1; // 有向图
const DN = 2; // 有向网
const UDG = 3; // 无向图
const UDN = 4; // 无向网
/*
邻接链表法
基本思想:对图的每个顶点建立一个单链表,存储该顶点所有邻接顶点及其相关信息。每一个单链表设一个表头结点。
第i个单链表表示依附于顶点Vi的边(对有向图是以顶点Vi为头或尾的弧)。
1 结点结构与邻接链表示例
链表中的结点称为表结点,每个结点由三个域组成。其中邻接点域(adjvex)指示与顶点Vi邻接的顶点在图中的位置(顶点编号),链域(nextarc)指向下一个与顶点Vi邻接的表结点,数据域(info)存储和边或弧相关的信息,如权值等。对于无权图,如果没有与边相关的其他信息,可省略此域。
每个链表设一个表头结点(称为顶点结点),由两个域组成。链域(firstarc)指向链表中的第一个结点,数据域(data) 存储顶点名或其他信息。
在图的邻接链表表示中,所有顶点结点用一个向量 以顺序结构形式存储,可以随机访问任意顶点的链表,该向量称为表头向量,向量的下标指示顶点的序号。
用邻接链表存储图时,对无向图,其邻接链表是唯一的;对有向图,其邻接链表有两种形式。
2 邻接表法的特点
◆ 表头向量中每个分量就是一个单链表的头结点,分量个数就是图中的顶点数目;
◆ 在边或弧稀疏的条件下,用邻接表表示比用邻接矩阵表示节省存储空间;
◆ 在无向图,顶点Vi的度是第i个链表的结点数;
◆ 对有向图可以建立正邻接表或逆邻接表。正邻接表是以顶点Vi为出度(即为弧的起点)而建立的邻接表;逆邻接表是以顶点Vi为入度(即为弧的终点)而建立的邻接表;
◆ 在有向图中,第i个链表中的结点数是顶点Vi的出 (或入)度;求入 (或出)度,须遍历整个邻接表;
◆ 在邻接表上容易找出任一顶点的第一个邻接点和下一个邻接点;
*/
class ArcNode {
/**
*
* @param {Number} adjVex
* @param {ArcNode} nextArc
* @param {*} info
* @constructor
*/
constructor(adjVex = 0, nextArc = null, info = null){
// 该弧所指向的顶点的位置
this.adjVex = adjVex;
// 指向下一条弧的指针
this.nextArc = nextArc;
// 该弧相关信息的指针
this.info = info;
}
}
class VexNode {
/**
*
* @param {*} data
* @param {ArcNode} firstArc
* @param {Number} indegree
* @constructor
*/
constructor(data, firstArc = null, indegree = 0){
// 顶点信息
this.data = data;
// 指向第一条依附该顶点的弧的指针
this.firstArc = firstArc;
// 顶点的度, 有向图是入度或出度或没有
this.indegree = indegree;
}
}
export default class AdjacencyListGraph {
/**
*
* @param {Array | VexNode} vertices
* @param {Number} vexnum
* @param {Number} arcnum
* @param {Number} kind
* @constructor
*/
constructor(vertices = [], vexnum = 0, arcnum = 0, kind = DG){
this.vertices = vertices;
// 图的当前顶点数和弧数
this.vexnum = vexnum;
this.arcnum = arcnum;
// 图的种类标志
this.kind = kind;
}
// 查找顶点位置
locateVex(vp) {
for (let i = 0; i < this.vexnum; ++i) {
if (this.vertices[i].data === vp) return i;
}
return -1;
}
// 添加顶点
addVertex(vp) {
if (this.locateVex(vp) !== -1) throw new Error('Vertex has existed!');
this.vertices[this.vexnum++] = new VexNode(vp, null, 0);
return this.vexnum;
}
/**
* 添加弧
* 如果是无向图或者无向网,arc1和arc2无顺序要求
* 如果是有向图或者有向网,只会添加arc1,因此正邻接表和逆邻接表的顺序需要注意
* @param {String} arc1
* @param {String} arc2
* @param {*} info
* @returns {boolean}
*/
addArc(arc1, arc2, info) {
let k = this.locateVex(arc1);
let j = this.locateVex(arc2);
if (k === -1 || j === -1) throw new Error('Arc\'s Vertex do not existed!');
// 边的起始表结点赋值
let p = new ArcNode(k, null, info);
// 边的末尾表结点赋值
let q = new ArcNode(j, null, info);
// 是无向图,用头插入法插入到两个单链表
if (this.kind === UDG || this.kind === UDN) {
q.nextArc = this.vertices[k].firstArc;
this.vertices[k].firstArc = q;
p.nextArc = this.vertices[j].firstArc;
this.vertices[j].firstArc = p;
}
// 建立有向图的邻接链表,用头插入法
else {
p.nextArc = this.vertices[j].firstArc;
this.vertices[j].firstArc = p;
}
++this.arcnum;
return true;
}
// TODO 其他图类型的创建暂时没弄
createGraph() {
this.vexnum = +prompt('vexnum: ');
this.arcnum = +prompt('arcnum: ');
// incInfo为0则各弧不含其他信息
let incInfo = +prompt('incInfo: ');
for (let m = 0; m < this.vexnum; ++m) {
this.vertices[m] = new VexNode();
this.vertices[m].data = prompt('vertex: ');
}
for (m = 0; m < this.arcnum; ++m) {
let h = prompt('弧头: ');
let t = prompt('弧尾: ');
let i = this.locateVex(t);
let j = this.locateVex(h);
if (i < 0 || j < 0) {
alert('顶点为找到,请重新输入!');
m--;
continue;
}
let p = new ArcNode(j, null, incInfo && prompt('info: '));
if (!this.vertices[i].firstArc) this.vertices[i].firstArc = p;
else {
for (let q = this.vertices[i].firstArc; q.nextArc; q = q.nextArc);
q.nextArc = p;
}
}
}
// 判断一个邻接表存储的有向图是否可传递
isPass() {
if (this.kind !== DG) throw new Error('graph kind should be DG');
for (let x = 0; x < this.vexnum; ++x) {
for (let p = this.vertices[x].firstArc; p; p = p.nextArc) {
let y = p.adjVex;
for (let q = this.vertices[y].firstArc; q; q = q.nextArc) {
let z = q.adjVex;
if (z !== x && this.isAdj(x, z)) return false;
}
}
}
return true;
}
// 判断有向图是否存在边(m,n)
isAdj(m, n) {
for (let p = this.vertices[m].firstArc; p; p = p.nextArc) {
if (p.adjVex === n) return true;
}
return false;
}
/**
* 深度优先判断<b>有向图<b>的顶点i到顶点j是否有路径,实则返回true,否则返回false
* @param {String} i
* @param {String} j
*/
existPathDFS(i, j) {
let visited = [];
i = this.locateVex(i);
j = this.locateVex(j);
if (i < 0 || j < 0) throw new Error('vertex not found!');
return exist_path(this, i, j);
function exist_path(graph, i, j) {
if (i === j) return true;
visited[i] = true;
for (let p = graph.vertices[i].firstArc; p; p = p.nextArc) {
let k = p.adjVex;
if (!visited[k] && exist_path(graph, k, j)) return true;
}
return false;
}
}
/**
* 广度优先判断<b>有向图<b>的顶点i到顶点j是否有路径,实则返回true,否则返回false
* @param {String} i
* @param {String} j
*/
existPathBFS(i, j) {
i = this.locateVex(i);
j = this.locateVex(j);
let visited = [];
let queue = new Queue();
queue.enQueue(i);
while (queue.rear) {
let u = queue.deQueue();
visited[u] = 1;
for (let p = this.vertices[i].firstArc; p; p = p.nextArc) {
let k = p.adjVex;
if (k === j) return true;
if (!visited[k]) queue.enQueue(k);
}
}
return false;
}
/**
* 判断邻接表方式存储的有向图的顶点i到j是否存在长度为k的简单路径
* @param {String} i
* @param {String} j
* @param {Number} k
*/
existPathLen(i, j, k) {
i = this.locateVex(i);
j = this.locateVex(j);
let visited = [];
return (function recurse(graph, i, j, k) {
// 找到了一条路径,且长度符合
if (i === j && k === 0) return true;
else if (k > 0) {
visited[i] = 1;
for (let p = graph.vertices[i].firstArc; p; p = p.nextArc) {
let l = p.adjVex;
if (!visited[l]) {
// 剩余路径长度减一
if (recurse(graph, l, j, k - 1)) return true;
}
}
// 允许曾经被访问过的结点出现在另一条路径上
visited[i] = 0;
}
return false;
})(this, i, j, k);
}
/**
* 求有向图中顶点u到v之间的所有简单路径,k为当前路径长度
* @param {String} u
* @param {String} v
* @param {Number} k
*
* @example
* graph.findAllPaths('v1', 'v2', 0);
*/
findAllPaths(u, v, k) {
u = this.locateVex(u);
v = this.locateVex(v);
let path = [];
let visited = [];
findPath(this, u, v, k);
function findPath(graph, u, v, k) {
// 加入当前路径中
path[k] = u;
visited[u] = 1;
// 找到一条简单路径
if (u === v) {
console.log('Found one path!');
for (let i = 0; path[i]; ++i) console.log(path[i]);
} else {
for (let p = graph.vertices[u].firstArc; p; p = p.nextArc) {
let l = p.adjVex;
// 继续寻找
if (!visited[l]) findPath(graph, l, v, k + 1);
}
}
visited[u] = 0;
// 回溯
path[k] = 0;
}
}
/**
* 求有向图的顶点之间长度为len的简单路径条数
* @param {String} i
* @param {String} j
* @param {Number} len
*/
getPathNum_len(i, j, len) {
let visited = [];
return (function recurse(graph, i, j, len) {
if (i === j && len === 0) return 1;
else if (len > 0) {
let sum = 0;
visited[i] = 1;
for (let p = graph.vertices[i].firstArc; p; p = p.nextArc) {
let l = p.adjVex;
if (!visited[l]) sum += recurse(l, j, len - 1);
}
visited[i] = 0;
return sum;
}
})(this, i, j, len);
}
/**
* 求有向无环图的根
*/
getRoot(){
let visited = [];
for(let i = 0; i < this.vexnum; ++i) {
// 每次都要将访问数组清零
for (let w = 0; w < this.vexnum; ++w) visited[w] = false;
// 从顶点i出发进行深度优先遍历
dfs(this, i);
let flag = true;
for(w = 0; w < this.vexnum; ++w){
// 如果i是根,则深度优先遍历可以访问到所有结点
if(!visited[w]) flag = false;
}
if(flag) console.log('Found a root vertex: %d', i);
}
function dfs(graph, v){
visited[v] = true;
for(let p = graph.vertices[v].firstArc; p; p = p.nextArc){
let w = p.adjVex;
if(!visited[w]) dfs(graph, w);
}
}
}
/**
* 求一个有向无环图中最长的路径
*/
getLongestPath(){
let mlp = [];
let path = [];
let visited = [];
let maxLen = 0;
this.countIndegree();
for(let i = 0; i < this.vexnum; ++i) {
for (let j = 0; j < this.vexnum; ++j) visited[j] = false;
// 从每一个零入度结点开始深度优先遍历
if (this.vertices[i].indegree === 0) dfs(this, i, 0);
}
console.log('Longest Path:');
// 输出最长路径
for(i = 0; mlp[i]; ++i) console.log(mlp.join(','));
function dfs(graph, i, len){
visited[i] = true;
path[len] = i;
// 新的最长路径
if(len > maxLen && !graph.vertices[i].firstArc) {
// 保存下来
for(let j = 0; j <= len; ++j) mlp[j] = path[j];
maxLen = len;
} else {
for(let p = graph.vertices[i].firstArc; p; p = p.nextArc){
let w = p.adjVex;
if(!visited[w]) dfs(graph, w, len + 1);
}
}
path[i] = 0;
visited[i] = false;
}
}
// 邻接表的递归式深度优先遍历
DFSTraverse(visitFn) {
let visited = [];
for (let i = 0; i < this.vexnum; ++i) visited[i] = false;
for (let i = 0; i < this.vexnum; ++i) {
if (!visited[i]) dfs(this, i);
}
function dfs(graph, v) {
visited[v] = true;
visitFn.call(graph, v);
let p = graph.vertices[v].firstArc;
while (p) {
if (!visited[p.adjVex]) dfs(graph, p.adjVex);
p = p.nextArc;
}
}
}
// 邻接表的非递归深度优先搜索
DFSTraverse_NonRecurse(visitFn) {
let visited = [];
let stack = new Stack();
for (let i = 0; i < this.vexnum; ++i) visited[i] = false;
for (let i = 0; i < this.vexnum; ++i) {
if (!visited[i]) {
stack.push(i);
visited[i] = true;
visitFn.call(this, i);
let v;
while ((v = stack.peek()) != null) {
let p = this.vertices[v].firstArc;
while (p) {
if (!visited[p.adjVex]) {
visited[p.adjVex] = true;
visitFn.call(this, p.adjVex);
stack.push(p.adjVex);
} else stack.pop();
p = p.nextArc;
}
}
}
}
}
// 邻接表的广度优先搜索
BFSTraverse(visitFn) {
let queue = new Queue();
let visited = [];
for (let i = 0; i < this.vexnum; ++i) visited[i] = false;
for (let i = 0; i < this.vexnum; ++i) {
if (!visited[i]) {
queue.enQueue(i);
visited[i] = true;
visitFn.call(this, i);
while (queue.rear) {
let w = queue.deQueue();
let p = this.vertices[w].firstArc;
while (p) {
if (!visited[p.adjVex]) {
visited[p.adjVex] = true;
visitFn.call(this, p.adjVex);
queue.enQueue(p.adjVex);
}
p = p.nextArc;
}
}
}
}
}
// 建立无向图的深度优先生成森林的孩子兄弟链表树
createDFSForest() {
let tree = null;
let visited = [];
for (let i = 0; i < this.vexnum; ++i) visited[i] = false;
let q;
for (let i = 0; i < this.vexnum; ++i) {
if (!visited[i]) {
// 新的生成树的根结点
let p = new ChildSiblingTree(this.vertices[i].data);
// 第一棵生成树的根
if (!tree) tree = p;
// 其它生成树的根
else q.nextSibling = p;
// q为当前生成树的根
q = p;
// 建立以p为根的生成树
DFSTree(this, i, p);
}
}
return tree;
// 以第v个顶点触发深度优先遍历图,建立以tree为根的生成树
function DFSTree(graph, v, tree) {
visited[v] = true;
let first = true;
let w = graph.vertices[v].firstArc;
let q;
while (w) {
if (!visited[w.adjVex]) {
visited[w.adjVex] = true;
let p = new ChildSiblingTree(graph.vertices[w.adjVex].data);
// w是v的第一个未被访问的邻接结点
if (first) {
tree.firstChild = p;
first = false;
}
// w是v的其它未被访问的邻接顶点
else q.nextSibling = p;
q = p;
DFSTree(graph, w.adjVex, q);
}
w = w.nextArc;
}
}
}
createBFSForest() {
let tree = null;
let visited = [];
let queue = new Queue();
for (let i = 0; i < this.vexnum; ++i) visited[i] = false;
let q;
for (let i = 0; i < this.vexnum; ++i) {
if (!visited[i]) {
visited[i] = true;
queue.enQueue(i);
let node = new ChildSiblingTree(this.vertices[i].data);
if (!tree) tree = node;
else q.nextSibling = node;
q = node;
while (queue.rear) {
let w = queue.deQueue();
let p = this.vertices[w].firstArc;
let first = true;
let pre;
while (p) {
if (!visited[p.adjVex]) {
visited[p.adjVex] = true;
queue.enQueue(p.adjVex);
let node2 = new ChildSiblingTree(this.vertices[p.adjVex].data);
if (first) {
node.firstChild = node2;
first = false;
}
else pre.nextSibling = node2;
pre = node2;
}
p = p.nextArc;
}
}
}
}
return tree;
}
findArticul() {
let visited = [];
let count = 1;
let low = [];
low[0] = count;
visited[0] = 1;
for (let i = 1; i < this.vexnum; ++i) visited[i] = 0;
let p = this.vertices[0].firstArc;
let v = p.adjVex;
DFSArticul(this, v);
if (count < this.vexnum) {
console.log(0 + ' ' + this.vertices[0].data);
while (p.nextArc) {
p = p.nextArc;
v = p.adjVex;
if (visited[v] === 0) DFSArticul(this, v);
}
}
function DFSArticul(graph, v0) {
let min = visited[v0] = ++count;
for (let p = graph.vertices[v0].firstArc; p; p = p.nextArc) {
let w = p.adjVex;
if (visited[w] === 0) {
DFSArticul(graph, w);
if (low[w] < min) min = low[w];
if (low[w] >= visited[v0]) console.log(v0 + ' ' + graph.vertices[v0].data);
} else if (visited[w] < min) min = visited[w];
}
low[v0] = min;
}
}
// 统计各顶点入度的函数
countIndegree() {
for (let k = 0; k < this.vexnum; ++k) this.vertices[k].indegree = 0;
for (let k = 0; k < this.vexnum; ++k) {
for (let p = this.vertices[k].firstArc; p; p = p.nextArc)
++this.vertices[p.adjVex].indegree;
}
}
// 拓扑排序算法
topologicSort() {
let stack = new Stack();
this.topologicalOrder = [];
this.countIndegree();
for (let i = 0; i < this.vexnum; ++i) {
if (this.vertices[i].indegree === 0) stack.push(i);
}
let count = 0;
while (stack.length) {
let i = stack.pop();
this.topologicalOrder.push(i);
console.log(this.vertices[i].data);
++count;
for (let p = this.vertices[i].firstArc; p; p = p.nextArc) {
let k = p.adjVex;
if (--this.vertices[k].indegree === 0) stack.push(k);
}
}
return (count >= this.vexnum);
}
// 输出有向图的各项关键活动
criticalPath() {
if (!this.topologicSort()) throw new Error('AOE网中存在回路!');
let ve = [];
// 事件最早发生时间初始化
for (let j = 0; j < this.vexnum; ++j) ve[j] = 0;
// 计算每个事件的最早发生时间ve值
for (let m = 0; m < this.vexnum; ++m) {
let j = this.topologicalOrder[m];
for (let p = this.vertices[j].firstArc; p; p = p.nextArc) {
let k = p.adjVex;
if (ve[j] + p.info > ve[k]) ve[k] = ve[j] + p.info;
}
}
let vl = [];
// 事件最晚发生时间初始化
for (let j = 0; j < this.vexnum; ++j) vl[j] = ve[this.vexnum - 1];
// 计算每个事件的最晚发生时间vl的值
for (let m = this.vexnum - 1; m >= 0; --m) {
let j = this.topologicalOrder[m];
for (let p = this.vertices[j].firstArc; p; p = p.nextArc) {
let k = p.adjVex;
if (vl[k] - p.info < vl[j]) vl[j] = vl[k] - p.info;
}
}
// 输出所有关键活动
for (let m = 0; m < this.vexnum; ++m) {
for (let p = this.vertices[m].firstArc; p; p = p.nextArc) {
let k = p.adjVex;
if (ve[m] + p.info === vl[k]) console.log('<%d, %d>', m, k);
}
}
}
shortestPath_Dijkstra(v0) {
let dist = [];
let pre = [];
let final = [];
let w;
for (let v = 0; v < this.vexnum; ++v)
dist[v] = Infinity;
for (let p = this.vertices[v0].firstArc; p; p = p.nextArc)
dist[p.adjVex] = p.info;
let v;
for (v = 0; v < this.vexnum; ++v) {
final[v] = false;
pre[v] = pre[v] || [];
for (w = 0; w < this.vexnum; ++w) pre[v][w] = false;
if (dist[v] < Infinity) {
pre[v][v0] = true;
pre[v][v] = true;
}
}
dist[v0] = 0;
final[v0] = true;
for (let i = 1; i < this.vexnum; ++i) {
let min = Infinity;
for (w = 0; w < this.vexnum; ++w) {
if (!final[w] && dist[w] < min) {
v = w;
min = dist[w];
}
}
final[v] = true;
for (let p = this.vertices[v].firstArc; p; p = p.nextArc) {
w = p.adjVex;
if (!final[w] && min + p.info < dist[w]) {
dist[w] = min + p.info;
pre[w] = pre[v];
pre[w][w] = true;
}
}
}
console.log(final);
console.log(pre);
console.log(dist);
return {
final: final,
pre: pre,
dist: dist
};
}
}
// 无向图的邻接表
var adjListGraph = new AdjacencyListGraph([], 0, 0, UDG);
adjListGraph.addVertex('v1');
adjListGraph.addVertex('v2');
adjListGraph.addVertex('v3');
adjListGraph.addVertex('v4');
adjListGraph.addVertex('v5');
adjListGraph.addArc('v1', 'v2');
adjListGraph.addArc('v1', 'v3');
adjListGraph.addArc('v1', 'v4');
adjListGraph.addArc('v2', 'v3');
adjListGraph.addArc('v3', 'v4');
adjListGraph.addArc('v3', 'v5');
adjListGraph.addArc('v4', 'v5');
console.log(adjListGraph);
// 有向图的逆邻接表
var g = new AdjacencyListGraph([], 0, 0, DG);
g.addVertex('v1');
g.addVertex('v2');
g.addVertex('v3');
g.addVertex('v4');
g.addVertex('v5');
g.addArc('v1', 'v2');
g.addArc('v1', 'v4');
g.addArc('v3', 'v2');
g.addArc('v3', 'v1');
g.addArc('v4', 'v3');
g.addArc('v3', 'v5');
g.addArc('v5', 'v4');
console.log(g);
// 有向图的正邻接表
var g = new AdjacencyListGraph([], 0, 0, DG);
g.addVertex('v1');
g.addVertex('v2');
g.addVertex('v3');
g.addVertex('v4');
g.addVertex('v5');
g.addArc('v2', 'v1');
g.addArc('v4', 'v1');
g.addArc('v2', 'v3');
g.addArc('v1', 'v3');
g.addArc('v3', 'v4');
g.addArc('v5', 'v3');
g.addArc('v4', 'v5');
console.log(g);
console.log('adjListGraph DFSTraverse: ');
var adjListGraph = new AdjacencyListGraph([], 0, 0, UDG);
adjListGraph.addVertex('v1');
adjListGraph.addVertex('v2');
adjListGraph.addVertex('v3');
adjListGraph.addVertex('v4');
adjListGraph.addVertex('v5');
adjListGraph.addArc('v5', 'v4');
adjListGraph.addArc('v3', 'v2');
adjListGraph.addArc('v2', 'v1');
adjListGraph.addArc('v3', 'v1');
adjListGraph.DFSTraverse(function (v) {
console.log(this.vertices[v].data);
});
console.log('adjListGraph DFSTraverse_NonRecurse: ');
adjListGraph.DFSTraverse_NonRecurse(function (v) {
console.log(this.vertices[v].data);
});
console.log('adjListGraph BFSTraverse: ');
var g2 = new AdjacencyListGraph([], 0, 0, DG);
g2.addVertex('v1');
g2.addVertex('v2');
g2.addVertex('v3');
g2.addVertex('v4');
g2.addVertex('v5');
g2.addArc('v4', 'v1');
g2.addArc('v2', 'v1');
g2.addArc('v5', 'v3');
g2.addArc('v2', 'v3');
g2.addArc('v1', 'v3');
g2.addArc('v3', 'v4');
g2.addArc('v4', 'v5');
g2.BFSTraverse(function (v) {
console.log(this.vertices[v].data);
});
console.log('DFS: expect false: ' + adjListGraph.existPathDFS('v1', 'v4'));
console.log('DFS: expect true: ' + adjListGraph.existPathDFS('v1', 'v2'));
console.log('BFS : expect false: ' + adjListGraph.existPathBFS('v1', 'v4'));
console.log('BFS :expect true: ' + adjListGraph.existPathBFS('v1', 'v2'));
/*
图的连通性问题
无向图的连通分量与生成树
1 无向图的连通分量和生成树
对于无向图,对其进行遍历时:
◆ 若是连通图:仅需从图中任一顶点出发,就能访问图中的所有顶点;
◆ 若是非连通图:需从图中多个顶点出发。每次从一个新顶点出发所访问的顶点集序列恰好是各个连通分量的顶点集;
⑴ 若G=(V,E)是无向连通图, 顶点集和边集分别是V(G) ,E(G) 。若从G中任意点出发遍历时, E(G)被分成两个互不相交的集合:
T(G) :遍历过程中所经过的边的集合;
B(G) :遍历过程中未经过的边的集合;
显然: E(G)=T(G)∪B(G) ,T(G)∩B(G)=Ø
显然,图G’=(V, T(G))是G的极小连通子图,且G’是一棵树。G’称为图G的一棵生成树。
从任意点出发按DFS算法得到生成树G’称为深度优先生成树;按BFS算法得到的G’称为广度优先生成树。
⑵ 若G=(V,E)是无向非连通图,对图进行遍历时得到若干个连通分量的顶点集:V1(G) ,V2(G) ,…,Vn(G)和相应所经过的边集:T1(G) ,T2(G) , …,Tn(G) 。
则对应的顶点集和边集的二元组:Gi=(Vi(G),Ti(G))
(1≦i≦n)是对应分量的生成树,所有这些生成树构成了原来非连通图的生成森林。
说明:当给定无向图要求画出其对应的生成树或生成森林时,必须先给出相应的邻接表,然后才能根据邻接表画出其对应的生成树或生成森林。
2 图的生成树和生成森林算法
对图的深度优先搜索遍历DFS(或BFS)算法稍作修改,就可得到构造图的DFS生成树算法。
在算法中,树的存储结构采用孩子—兄弟表示法。首先建立从某个顶点V出发,建立一个树结点,然后再分别以V的邻接点为起始点,建立相应的子生成树,并将其作为V 结点的子树链接到V结点上。显然,算法是一个递归算法。
*/
console.log(adjListGraph.createDFSForest());
console.log(adjListGraph.createBFSForest());
/*
在某图中,若删除顶点V以及V相关的边后,图的一个连通分量分割为两个或两个以上的连通分量,则称顶点V为该图的一个关节点。一个没有关节点的连通图称为重连通图。
在重连通图中,任意一对顶点之间至少存在两条路径,则再删去某个顶点即相关各边后也不破坏图的连通性。若在图的连通图上删去k个节点才能破坏图的连通性,则称K为此图的连通度。
他们常常在通信网络的图或航空网中应用,K越大,系统越稳定,反之,战争中若要摧毁敌方的运输线,只须破坏其运输网中的关节点即可。
*/
var articulTest = new AdjacencyListGraph([], 0, 0, UDG);
articulTest.addVertex('A');
articulTest.addVertex('B');
articulTest.addVertex('C');
articulTest.addVertex('D');
articulTest.addVertex('E');
articulTest.addVertex('F');
articulTest.addVertex('G');
articulTest.addVertex('H');
articulTest.addVertex('I');
articulTest.addVertex('J');
articulTest.addVertex('K');
articulTest.addVertex('L');
articulTest.addVertex('M');
articulTest.addArc('A', 'B');
articulTest.addArc('A', 'C');
articulTest.addArc('A', 'F');
articulTest.addArc('A', 'L');
articulTest.addArc('C', 'B');
articulTest.addArc('D', 'B');
articulTest.addArc('G', 'B');
articulTest.addArc('H', 'B');
articulTest.addArc('M', 'B');
articulTest.addArc('D', 'E');
articulTest.addArc('G', 'H');
articulTest.addArc('G', 'I');
articulTest.addArc('G', 'K');
articulTest.addArc('H', 'K');
articulTest.addArc('J', 'L');
articulTest.addArc('J', 'M');
articulTest.addArc('L', 'M');
articulTest.findArticul();
/*
有向无环图及其应用
有向无环图(Directed Acycling Graph):是图中没有回路(环)的有向图。是一类具有代表性的图,主要用于研究工程项目的工序问题、工程时间进度问题等。
一个工程(project)都可分为若干个称为活动(active)的子工程(或工序),各个子工程受到一定的条件约束:某个子工程必须开始于另一个子工程完成之后;整个工程有一个开始点(起点)和一个终点。人们关心:
◆ 工程能否顺利完成?影响工程的关键活动是什么?
◆ 估算整个工程完成所必须的最短时间是多少?
对工程的活动加以抽象:图中顶点表示活动,有向边表示活动之间的优先关系,这样的有向图称为顶点表示活动的网(Activity On Vertex Network ,AOV网) 。
拓扑排序
1 定义
拓扑排序(Topological Sort) :由某个集合上的一个偏序得到该集合上的一个全序的操作。
◆ 集合上的关系:集合A上的关系是从A到A的关系(AA) 。
◆ 关系的自反性:若a∈A有(a,a)∈R,称集合A上的关系R是自反的。
◆ 关系的对称性:如果对于a,b∈A ,只要有(a,b)∈R就有(b,a)∈R ,称集合A上的关系R是对称的。
◆ 关系的对称性与反对称性:如果对于a,b∈A ,只要有(a,b)∈R就有(b,a)∈R ,称集合A上的关系R是对称的。如果对于a,b∈A ,仅当a=b时有(a,b)∈R和(b,a)∈R ,称集合A上的关系R是反对称的。