Passed
Push — master ( c21857...1d23cf )
by Yo
01:45
created

RecursiveReversedTraversal   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 132
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 19
c 1
b 0
f 0
dl 0
loc 132
ccs 24
cts 24
cp 1
rs 10
wmc 12

6 Methods

Rating   Name   Duplication   Size   Complexity  
A postOrderGenerator() 0 9 3
A inOrder() 0 5 1
A preOrder() 0 5 1
A inOrderGenerator() 0 10 3
A preOrderGenerator() 0 9 3
A postOrder() 0 5 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yoanm\CommonDSA\Algorithm\BinaryTree;
6
7
use Generator;
8
use Yoanm\CommonDSA\DataStructure\BinaryTree\NodeInterface as Node;
9
10
/**
11
 * Reversed binary tree traversal relying on recursive functions.<br>
12
 * ⚠ Recursive function implies a growing stack trace, which has a limited size!<br>
13
 * See {@see \Yoanm\CommonDSA\Algorithm\BinaryTree\ReversedTraversal} for iterative implementations.
14
 *
15
 *
16
 * <br>
17
 * ℹ Reversed level-order is not implemented as it implies to keep track of and look at each and every node in
18
 * order to detect the last level => Time and space complexity will be 𝑂⟮𝑛⟯ in any cases !<br>
19
 * Workaround:<br>
20
 * 1. Fetch the result of {@see \Yoanm\CommonDSA\Algorithm\BinaryTree\RecursiveTraversal::levelOrder}
21
 *    or {@see \Yoanm\CommonDSA\Algorithm\BinaryTree\RecursiveTraversal::levelOrderGenerator}
22
 * 2. Either start from the end or reverse the whole list (the latter implies
23
 *    an additional 𝑂⟮𝑛⟯ time complexity though !)
24
 *
25
 *
26
 * @see \Yoanm\CommonDSA\Algorithm\BinaryTree\ReversedTraversal for iterative implementations.
27
 */
28
class RecursiveReversedTraversal
29
{
30
    /**
31
     * @see \Yoanm\CommonDSA\Algorithm\BinaryTree\RecursiveReversedTraversal::preOrderGenerator()
32
     *
33
     *
34
     * @return array<Node>
35
     * @phpstan-return list<Node>
36
     */
37 2
    public static function preOrder(Node $node): array
38
    {
39
        // ⚠ Do not preserve keys otherwise there is conflicting keys in case "yield from" is used !
40
        // ⚠ Do not preserve keys in order to always return a list !
41 2
        return iterator_to_array(self::preOrderGenerator($node), false);
42
    }
43
44
    /**
45
     * @see \Yoanm\CommonDSA\Algorithm\BinaryTree\RecursiveReversedTraversal::preOrderGenerator()
46
     *
47
     *
48
     * @return array<Node>
49
     * @phpstan-return list<Node>
50
     */
51 2
    public static function inOrder(Node $node): array
52
    {
53
        // ⚠ Do not preserve keys otherwise there is conflicting keys in case "yield from" is used !
54
        // ⚠ Do not preserve keys in order to always return a list !
55 2
        return iterator_to_array(self::inOrderGenerator($node), false);
56
    }
57
58
    /**
59
     * @see \Yoanm\CommonDSA\Algorithm\BinaryTree\RecursiveReversedTraversal::inOrderGenerator()
60
     *
61
     *
62
     * @return array<Node>
63
     * @phpstan-return list<Node>
64
     */
65 2
    public static function postOrder(Node $node): array
66
    {
67
        // ⚠ Do not preserve keys otherwise there is conflicting keys in case "yield from" is used !
68
        // ⚠ Do not preserve keys in order to always return a list !
69 2
        return iterator_to_array(self::postOrderGenerator($node), false);
70
    }
71
72
    /**
73
     * Reversed Pre-order: N->R->L => Node, then Right children, then Left children
74
     *
75
     *
76
     * <br>
77
     * ### Time/Space complexity
78
     * With:
79
     * - 𝑛 the number of node in the tree
80
     * - 𝘩 the tree height, usually ㏒(𝑛) (=balanced tree).<br>
81
     *   ⚠ 𝘩 = 𝑛 if every node has only a right child (skewed tree)
82
     *
83
     * TC: 𝑂⟮𝑛⟯ - Each node will be visited only one time
84
     *
85
     * SC: 𝑂⟮𝘩⟯ - Due to the stack trace (recursive calls) + extra space for inner Generator class instances !
86
     *
87
     *
88
     * @return Generator<Node>
89
     */
90 4
    public static function preOrderGenerator(Node $node): Generator
91
    {
92 4
        yield $node;
93
94 4
        if (null !== $node->right) {
95 4
            yield from self::preOrderGenerator($node->right);
96
        }
97 4
        if (null !== $node->left) {
98 4
            yield from self::preOrderGenerator($node->left);
99
        }
100
    }
101
102
    /**
103
     * Reversed In-order (=Reversed DFS): R->N->L => Right children, then Node, then Left children
104
     *
105
     *
106
     * <br>
107
     * ### Time/Space complexity
108
     * With:
109
     * - 𝑛 the number of node in the tree
110
     * - 𝘩 the tree height, usually ㏒(𝑛) (=balanced tree).<br>
111
     *   ⚠ 𝘩 = 𝑛 if every node has only a right child (skewed tree)
112
     *
113
     * TC: 𝑂⟮𝑛⟯ - Each node will be visited only one time
114
     *
115
     * SC: 𝑂⟮𝘩⟯ - Due to the stack trace (recursive calls) + extra space for inner Generator class instances !
116
     *
117
     *
118
     * @return Generator<Node>
119
     */
120 4
    public static function inOrderGenerator(Node $node): Generator
121
    {
122 4
        if (null !== $node->right) {
123 4
            yield from self::inOrderGenerator($node->right);
124
        }
125
126 4
        yield $node;
127
128 4
        if (null !== $node->left) {
129 4
            yield from self::inOrderGenerator($node->left);
130
        }
131
    }
132
133
    /**
134
     * Reversed Post-order: R->L->N => Right children, then Left children, then Node
135
     *
136
     *
137
     * <br>
138
     * ### Time/Space complexity
139
     * With:
140
     * - 𝑛 the number of node in the tree
141
     * - 𝘩 the tree height, usually ㏒(𝑛) (=balanced tree).<br>
142
     *   ⚠ 𝘩 = 𝑛 if every node has only a right child (skewed tree)
143
     *
144
     * TC: 𝑂⟮𝑛⟯ - Each node will be visited only one time
145
     *
146
     * SC: 𝑂⟮𝘩⟯ - Due to the stack trace (recursive calls) + extra space for inner Generator class instances !
147
     *
148
     *
149
     * @return Generator<Node>
150
     */
151 4
    public static function postOrderGenerator(Node $node): Generator
152
    {
153 4
        if (null !== $node->right) {
154 4
            yield from self::postOrderGenerator($node->right);
155
        }
156 4
        if (null !== $node->left) {
157 4
            yield from self::postOrderGenerator($node->left);
158
        }
159 4
        yield $node;
160
    }
161
}
162