@@ -363,7 +363,7 @@ public Iterable<N> depthFirstPreOrder(final Iterable<? extends N> startNodes) {
363
363
return new Iterable <N >() {
364
364
@ Override
365
365
public Iterator <N > iterator () {
366
- return new DepthFirstIterator ( startNodes , Order . PREORDER );
366
+ return Walker . inGraph ( graph ). preOrder ( startNodes . iterator () );
367
367
}
368
368
};
369
369
}
@@ -386,7 +386,7 @@ public Iterable<N> depthFirstPostOrder(final Iterable<? extends N> startNodes) {
386
386
return new Iterable <N >() {
387
387
@ Override
388
388
public Iterator <N > iterator () {
389
- return new DepthFirstIterator ( startNodes , Order . POSTORDER );
389
+ return Walker . inGraph ( graph ). postOrder ( startNodes . iterator () );
390
390
}
391
391
};
392
392
}
@@ -427,58 +427,6 @@ public N next() {
427
427
return current ;
428
428
}
429
429
}
430
-
431
- private final class DepthFirstIterator extends AbstractIterator <N > {
432
- private final Deque <NodeAndSuccessors > stack = new ArrayDeque <>();
433
- private final Set <N > visited = new HashSet <>();
434
- private final Order order ;
435
-
436
- DepthFirstIterator (Iterable <? extends N > roots , Order order ) {
437
- stack .push (new NodeAndSuccessors (null , roots ));
438
- this .order = order ;
439
- }
440
-
441
- @ Override
442
- protected N computeNext () {
443
- while (true ) {
444
- if (stack .isEmpty ()) {
445
- return endOfData ();
446
- }
447
- NodeAndSuccessors nodeAndSuccessors = stack .getFirst ();
448
- boolean firstVisit = visited .add (nodeAndSuccessors .node );
449
- boolean lastVisit = !nodeAndSuccessors .successorIterator .hasNext ();
450
- boolean produceNode =
451
- (firstVisit && order == Order .PREORDER ) || (lastVisit && order == Order .POSTORDER );
452
- if (lastVisit ) {
453
- stack .pop ();
454
- } else {
455
- // we need to push a neighbor, but only if we haven't already seen it
456
- N successor = nodeAndSuccessors .successorIterator .next ();
457
- if (!visited .contains (successor )) {
458
- stack .push (withSuccessors (successor ));
459
- }
460
- }
461
- if (produceNode && nodeAndSuccessors .node != null ) {
462
- return nodeAndSuccessors .node ;
463
- }
464
- }
465
- }
466
-
467
- NodeAndSuccessors withSuccessors (N node ) {
468
- return new NodeAndSuccessors (node , graph .successors (node ));
469
- }
470
-
471
- /** A simple tuple of a node and a partially iterated {@link Iterator} of its successors. */
472
- private final class NodeAndSuccessors {
473
- @ NullableDecl final N node ;
474
- final Iterator <? extends N > successorIterator ;
475
-
476
- NodeAndSuccessors (@ NullableDecl N node , Iterable <? extends N > successors ) {
477
- this .node = node ;
478
- this .successorIterator = successors .iterator ();
479
- }
480
- }
481
- }
482
430
}
483
431
484
432
private static final class TreeTraverser <N > extends Traverser <N > {
@@ -529,7 +477,7 @@ public Iterable<N> depthFirstPreOrder(final Iterable<? extends N> startNodes) {
529
477
return new Iterable <N >() {
530
478
@ Override
531
479
public Iterator <N > iterator () {
532
- return new DepthFirstPreOrderIterator ( startNodes );
480
+ return Walker . inTree ( tree ). preOrder ( startNodes . iterator () );
533
481
}
534
482
};
535
483
}
@@ -552,7 +500,7 @@ public Iterable<N> depthFirstPostOrder(final Iterable<? extends N> startNodes) {
552
500
return new Iterable <N >() {
553
501
@ Override
554
502
public Iterator <N > iterator () {
555
- return new DepthFirstPostOrderIterator ( startNodes );
503
+ return Walker . inTree ( tree ). postOrder ( startNodes . iterator () );
556
504
}
557
505
};
558
506
}
@@ -585,77 +533,106 @@ public N next() {
585
533
return current ;
586
534
}
587
535
}
536
+ }
588
537
589
- private final class DepthFirstPreOrderIterator extends UnmodifiableIterator <N > {
590
- private final Deque <Iterator <? extends N >> stack = new ArrayDeque <>();
591
-
592
- DepthFirstPreOrderIterator (Iterable <? extends N > roots ) {
593
- stack .addLast (roots .iterator ());
594
- }
595
-
596
- @ Override
597
- public boolean hasNext () {
598
- return !stack .isEmpty ();
599
- }
538
+ /**
539
+ * Abstracts away the difference between traversing a graph vs. a tree. For a tree, we just take
540
+ * the next element from the next non-empty iterator; for graph, we need to loop through the next
541
+ * non-empty iterator to find first unvisited node.
542
+ */
543
+ private abstract static class Walker <N > {
544
+ final SuccessorsFunction <N > successorFunction ;
600
545
601
- @ Override
602
- public N next () {
603
- Iterator <? extends N > iterator = stack .getLast (); // throws NoSuchElementException if empty
604
- N result = checkNotNull (iterator .next ());
605
- if (!iterator .hasNext ()) {
606
- stack .removeLast ();
607
- }
608
- Iterator <? extends N > childIterator = tree .successors (result ).iterator ();
609
- if (childIterator .hasNext ()) {
610
- stack .addLast (childIterator );
611
- }
612
- return result ;
613
- }
546
+ Walker (SuccessorsFunction <N > successorFunction ) {
547
+ this .successorFunction = checkNotNull (successorFunction );
614
548
}
615
549
616
- private final class DepthFirstPostOrderIterator extends AbstractIterator <N > {
617
- private final ArrayDeque <NodeAndChildren > stack = new ArrayDeque <>();
618
-
619
- DepthFirstPostOrderIterator (Iterable <? extends N > roots ) {
620
- stack .addLast (new NodeAndChildren (null , roots ));
621
- }
622
-
623
- @ Override
624
- protected N computeNext () {
625
- while (!stack .isEmpty ()) {
626
- NodeAndChildren top = stack .getLast ();
627
- if (top .childIterator .hasNext ()) {
628
- N child = top .childIterator .next ();
629
- stack .addLast (withChildren (child ));
630
- } else {
631
- stack .removeLast ();
632
- if (top .node != null ) {
633
- return top .node ;
550
+ static <N > Walker <N > inGraph (SuccessorsFunction <N > graph ) {
551
+ final Set <N > visited = new HashSet <>();
552
+ return new Walker <N >(graph ) {
553
+ @ Override
554
+ N visitNext (Deque <Iterator <? extends N >> horizon ) {
555
+ Iterator <? extends N > top = horizon .getFirst ();
556
+ while (top .hasNext ()) {
557
+ N element = checkNotNull (top .next ());
558
+ if (visited .add (element )) {
559
+ return element ;
634
560
}
635
561
}
562
+ horizon .removeFirst ();
563
+ return null ;
636
564
}
637
- return endOfData () ;
638
- }
565
+ } ;
566
+ }
639
567
640
- NodeAndChildren withChildren (N node ) {
641
- return new NodeAndChildren (node , tree .successors (node ));
642
- }
568
+ static <N > Walker <N > inTree (SuccessorsFunction <N > tree ) {
569
+ return new Walker <N >(tree ) {
570
+ @ Override
571
+ N visitNext (Deque <Iterator <? extends N >> horizon ) {
572
+ Iterator <? extends N > top = horizon .getFirst ();
573
+ if (top .hasNext ()) {
574
+ return checkNotNull (top .next ());
575
+ }
576
+ horizon .removeFirst ();
577
+ return null ;
578
+ }
579
+ };
580
+ }
643
581
644
- /** A simple tuple of a node and a partially iterated {@link Iterator} of its children. */
645
- private final class NodeAndChildren {
646
- @ NullableDecl final N node ;
647
- final Iterator <? extends N > childIterator ;
582
+ final Iterator <N > preOrder (Iterator <? extends N > startNodes ) {
583
+ final Deque <Iterator <? extends N >> horizon = new ArrayDeque <>();
584
+ horizon .addFirst (startNodes );
585
+ return new AbstractIterator <N >() {
586
+ @ Override
587
+ protected N computeNext () {
588
+ do {
589
+ N next = visitNext (horizon );
590
+ if (next != null ) {
591
+ Iterator <? extends N > successors = successorFunction .successors (next ).iterator ();
592
+ if (successors .hasNext ()) {
593
+ horizon .addFirst (successors );
594
+ }
595
+ return next ;
596
+ }
597
+ } while (!horizon .isEmpty ());
598
+ return endOfData ();
599
+ }
600
+ };
601
+ }
648
602
649
- NodeAndChildren (@ NullableDecl N node , Iterable <? extends N > children ) {
650
- this .node = node ;
651
- this .childIterator = children .iterator ();
603
+ final Iterator <N > postOrder (Iterator <? extends N > startNodes ) {
604
+ final Deque <Iterator <? extends N >> horizon = new ArrayDeque <>();
605
+ horizon .addFirst (startNodes );
606
+ final Deque <N > ancestorStack = new ArrayDeque <>();
607
+ return new AbstractIterator <N >() {
608
+ @ Override
609
+ protected N computeNext () {
610
+ for (N next = visitNext (horizon ); next != null ; next = visitNext (horizon )) {
611
+ Iterator <? extends N > successors = successorFunction .successors (next ).iterator ();
612
+ if (!successors .hasNext ()) {
613
+ return next ;
614
+ }
615
+ horizon .addFirst (successors );
616
+ ancestorStack .push (next );
617
+ }
618
+ return ancestorStack .isEmpty () ? endOfData () : ancestorStack .pop ();
652
619
}
653
- }
620
+ };
654
621
}
655
- }
656
622
657
- private enum Order {
658
- PREORDER ,
659
- POSTORDER
623
+ /**
624
+ * Visits the next node from the top iterator of {@code horizon} and returns the visited node.
625
+ * Null is returned to indicate reaching the end of the top iterator, which can be used by the
626
+ * traversal strategies to decide what to return in such case: in pre-order, continue to poll
627
+ * the next top iterator with {@code visitNext()}; in post-order, return the parent node.
628
+ *
629
+ * <p>For example, if horizon is {@code [[a, b], [c, d], [e]]}, {@code visitNext()} will return
630
+ * {@code [a, b, null, c, d, null, e, null]} sequentially, encoding the topological structure.
631
+ * (Note, however, that the callers of {@code visitNext()} often insert additional iterators
632
+ * into {@code horizon} between calls to {@code visitNext()}. This causes them to receive
633
+ * additional values interleaved with those shown above.)
634
+ */
635
+ @ NullableDecl
636
+ abstract N visitNext (Deque <Iterator <? extends N >> horizon );
660
637
}
661
638
}
0 commit comments