1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | namespace MartanLV\Koki; |
||
6 | |||
7 | /** |
||
8 | * Augmented tree |
||
9 | * Class StaticTree. |
||
10 | * |
||
11 | * @author yourname |
||
12 | */ |
||
13 | class Tree extends Node |
||
14 | { |
||
15 | public $root; |
||
16 | |||
17 | /** |
||
18 | * undocumented function. |
||
19 | * |
||
20 | * @param $intervals array of Interval |
||
21 | * |
||
22 | * @return void |
||
23 | */ |
||
24 | public function __construct(array $intervals = [], bool $preSorted = false) |
||
25 | { |
||
26 | !$preSorted && usort($intervals, function (IntervalInterface $i0, IntervalInterface $i) { |
||
27 | return $i0->getStart() <=> $i->getStart(); |
||
28 | }); |
||
29 | $this->root = $this->toTree($intervals); |
||
30 | } |
||
31 | |||
32 | /** |
||
33 | * An augmented tree can be built from a simple ordered tree, |
||
34 | * for example a binary search tree or self-balancing binary search tree, |
||
35 | * ordered by the 'low' values of the intervals. |
||
36 | */ |
||
37 | public function toTree(array $intervals) |
||
38 | { |
||
39 | $max = 0; |
||
40 | $len = count($intervals); |
||
41 | $mid = (int) floor($len / 2); |
||
42 | |||
43 | if (!$len) { |
||
44 | return; |
||
45 | } |
||
46 | |||
47 | array_walk($intervals, function (IntervalInterface $el) use (&$max) { |
||
48 | if ($max < $el->getEnd()) { |
||
49 | $max = $el->getEnd(); |
||
50 | } |
||
51 | }); |
||
52 | $l_intervals = array_splice($intervals, 0, $mid); |
||
53 | $r_intervals = array_splice($intervals, -$mid); |
||
54 | $interval = $intervals ? reset($intervals) : array_pop($l_intervals); |
||
55 | $interval = $interval ?? array_pop($r_intervals); |
||
56 | |||
57 | $node = new Node( |
||
58 | $interval, |
||
59 | $this->toTree($l_intervals), |
||
60 | $this->toTree($r_intervals), |
||
61 | $max |
||
62 | ); |
||
63 | |||
64 | $node->root = &$this; |
||
65 | |||
66 | return $node; |
||
67 | } |
||
68 | |||
69 | /** |
||
70 | * returns intervals that exclusively fall within range given |
||
71 | * to retrieve eather bound inclusevely, just modify parameters. |
||
72 | * |
||
73 | * @return void |
||
74 | */ |
||
75 | public function select(int $low, int $high): array |
||
76 | { |
||
77 | return $this->root ? $this->root->select($low, $high) : []; |
||
0 ignored issues
–
show
Bug
Best Practice
introduced
by
![]() |
|||
78 | } |
||
79 | |||
80 | public function selectNode(int $low, int $high): array |
||
81 | { |
||
82 | return $this->root ? $this->root->selectNode($low, $high) : []; |
||
83 | } |
||
84 | |||
85 | /** |
||
86 | * rebalance messed up tree overall. |
||
87 | */ |
||
88 | public function balance() |
||
89 | { |
||
90 | // todo |
||
91 | } |
||
92 | |||
93 | /** |
||
94 | * understandable var dump. |
||
95 | */ |
||
96 | public function __debugInfo() |
||
97 | { |
||
98 | $arr = $this->all(); |
||
99 | |||
100 | usort($arr, function (IntervalInterface $i0, IntervalInterface $i) { |
||
101 | return $i0->getStart() <=> $i->getStart(); |
||
102 | }); |
||
103 | |||
104 | return $arr; |
||
105 | } |
||
106 | |||
107 | public function yieldInterSelect(int $low, int $high) |
||
108 | { |
||
109 | return $this->root ? $this->root->yieldInterSelect($low, $high) : []; |
||
110 | } |
||
111 | |||
112 | public function interSelectNode(int $low, int $high): array |
||
113 | { |
||
114 | return $this->root ? $this->root->interSelectNode($low, $high) : []; |
||
115 | } |
||
116 | |||
117 | public function interSelect(int $low, int $high): array |
||
118 | { |
||
119 | return $this->root ? $this->root->interSelect($low, $high) : []; |
||
120 | } |
||
121 | |||
122 | public function yieldSelect(int $low, int $high) |
||
123 | { |
||
124 | return $this->root ? $this->root->yieldSelect($low, $high) : []; |
||
125 | } |
||
126 | |||
127 | /** |
||
128 | * @return void |
||
129 | */ |
||
130 | public function all(): array |
||
131 | { |
||
132 | return $this->root ? $this->root->all() : []; |
||
0 ignored issues
–
show
|
|||
133 | } |
||
134 | |||
135 | /** |
||
136 | * undocumented function. |
||
137 | * |
||
138 | * @return void |
||
139 | */ |
||
140 | public function yieldAll() |
||
141 | { |
||
142 | return $this->root ? $this->root->yieldAll() : []; |
||
0 ignored issues
–
show
|
|||
143 | } |
||
144 | |||
145 | public function removeRegion(int $low, int $high) |
||
146 | { |
||
147 | if (!$this->root) { |
||
148 | return []; |
||
149 | } |
||
150 | foreach ($this->interSelectNode($low, $high) as $node) { |
||
151 | $this->remove($node); |
||
152 | } |
||
153 | } |
||
154 | |||
155 | public function remove(IntervalInterface $i) |
||
156 | { |
||
157 | if (!$i->left && !$i->right) { |
||
0 ignored issues
–
show
|
|||
158 | if ($i->root) { |
||
0 ignored issues
–
show
|
|||
159 | $i->root = null; |
||
160 | } |
||
161 | |||
162 | return; |
||
163 | } |
||
164 | |||
165 | if ($i->left && $i->right) { |
||
166 | // todo |
||
167 | return; |
||
168 | } |
||
169 | if ($i->left) { |
||
170 | $i->interval = &$i->left->interval; |
||
0 ignored issues
–
show
|
|||
171 | $i->left = null; |
||
172 | } |
||
173 | |||
174 | if ($i->right) { |
||
175 | } |
||
176 | |||
177 | if ($this->max > $i->getEnd()) { |
||
178 | if ($this->left) { |
||
179 | $this->left->add($i); |
||
180 | } else { |
||
181 | $this->left = new Node($i); |
||
182 | } |
||
183 | } else { |
||
184 | $this->max = $i->getEnd(); |
||
185 | if ($this->right) { |
||
186 | $this->right->add($i); |
||
187 | } else { |
||
188 | $this->right = new Node($i); |
||
189 | } |
||
190 | } |
||
191 | |||
192 | return; |
||
193 | if (!$this->root) { |
||
0 ignored issues
–
show
IfNode is not reachable.
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed. Unreachable code is most often the result of function fx() {
try {
doSomething();
return true;
}
catch (\Exception $e) {
return false;
}
return false;
}
In the above example, the last ![]() |
|||
194 | return []; |
||
195 | } |
||
196 | $this->root->remove($i); |
||
197 | } |
||
198 | |||
199 | public function add(IntervalInterface $i) |
||
200 | { |
||
201 | if (!$this->root) { |
||
202 | $this->root = new Node($i); |
||
203 | |||
204 | return; |
||
205 | } |
||
206 | $this->root->add($i); |
||
207 | } |
||
208 | } |
||
209 |