@@ -260,6 +260,23 @@ public function count(): int
260260 * @since 1.0.0
261261 */
262262 public function find ($ key , $ comparator , $ type = 0 )
263+ {
264+ list ($ node , $ cmp ) = $ this ->traverseForFind ($ key , $ comparator );
265+
266+ return $ this ->resolveFindResult ($ node , $ cmp , $ type );
267+ }
268+
269+ /**
270+ * Traverse tree for find operation
271+ *
272+ * @param mixed $key The searched key
273+ * @param callable $comparator The comparator function
274+ *
275+ * @return array{0: TreeNode, 1: integer} The closest node and comparison result
276+ *
277+ * @since 1.0.0
278+ */
279+ private function traverseForFind ($ key , $ comparator )
263280 {
264281 $ node = $ this ;
265282 $ cmp = 0 ;
@@ -276,31 +293,55 @@ public function find($key, $comparator, $type = 0)
276293 }
277294 }
278295
296+ return array ($ node , $ cmp );
297+ }
298+
299+ /**
300+ * Resolve find result from traversal state
301+ *
302+ * @param TreeNode $node The closest node
303+ * @param integer $cmp The key comparison result
304+ * @param integer $type The operation type
305+ *
306+ * @return mixed The resolved node or null
307+ *
308+ * @since 1.0.0
309+ */
310+ private function resolveFindResult ($ node , $ cmp , $ type )
311+ {
279312 if ($ cmp < 0 ) {
280313 if ($ type < 0 ) {
281314 return $ node ->left ;
282- } elseif ($ type > 0 ) {
315+ }
316+
317+ if ($ type > 0 ) {
283318 return $ node ;
284- } else {
285- return null ;
286319 }
287- } elseif ($ cmp > 0 ) {
320+
321+ return null ;
322+ }
323+
324+ if ($ cmp > 0 ) {
288325 if ($ type < 0 ) {
289326 return $ node ;
290- } elseif ($ type > 0 ) {
291- return $ node ->right ;
292- } else {
293- return null ;
294327 }
295- } else {
296- if ($ type < -1 ) {
297- return $ node ->predecessor ;
298- } elseif ($ type > 1 ) {
299- return $ node ->successor ;
300- } else {
301- return $ node ;
328+
329+ if ($ type > 0 ) {
330+ return $ node ->right ;
302331 }
332+
333+ return null ;
334+ }
335+
336+ if ($ type < -1 ) {
337+ return $ node ->predecessor ;
303338 }
339+
340+ if ($ type > 1 ) {
341+ return $ node ->successor ;
342+ }
343+
344+ return $ node ;
304345 }
305346
306347 /**
@@ -560,82 +601,132 @@ public function remove($key, $comparator)
560601 $ cmp = call_user_func ($ comparator , $ key , $ this ->keyInternal );
561602
562603 if ($ cmp < 0 ) {
563- if ( $ this ->information & 2 ) {
564- $ left = $ this -> left ;
604+ return $ this ->removeFromLeft ( $ key , $ comparator );
605+ }
565606
566- if (! $ left instanceof self ) {
567- return $ this ;
568- }
607+ if ($ cmp > 0 ) {
608+ return $ this -> removeFromRight ( $ key , $ comparator ) ;
609+ }
569610
570- $ leftBalance = $ left -> information & ~ 3 ;
571- $ this -> left = $ left -> remove ( $ key , $ comparator );
611+ return $ this -> removeCurrent () ;
612+ }
572613
573- if (
574- !($ this ->information & 2 )
575- || $ leftBalance != 0 && ($ this ->left instanceof self) && ($ this ->left ->information & ~3 ) == 0
576- ) {
577- return $ this ->incBalance ();
578- }
614+ /**
615+ * Remove from left subtree
616+ *
617+ * @param mixed $key The key
618+ * @param callable $comparator The comparator function
619+ *
620+ * @return TreeNode|null The new root
621+ *
622+ * @since 1.0.0
623+ */
624+ private function removeFromLeft ($ key , $ comparator )
625+ {
626+ if ($ this ->information & 2 ) {
627+ $ left = $ this ->left ;
628+
629+ if (!$ left instanceof self) {
630+ return $ this ;
579631 }
580- } elseif ($ cmp > 0 ) {
581- if ($ this ->information & 1 ) {
582- $ right = $ this ->right ;
583632
584- if (!$ right instanceof self) {
585- return $ this ;
586- }
633+ $ leftBalance = $ left ->information & ~3 ;
634+ $ this ->left = $ left ->remove ($ key , $ comparator );
587635
588- $ rightBalance = $ right ->information & ~3 ;
589- $ this ->right = $ right ->remove ($ key , $ comparator );
636+ if (
637+ !($ this ->information & 2 )
638+ || $ leftBalance != 0 && ($ this ->left instanceof self) && ($ this ->left ->information & ~3 ) == 0
639+ ) {
640+ return $ this ->incBalance ();
641+ }
642+ }
590643
591- if (
592- !($ this ->information & 1 )
593- || $ rightBalance != 0 && ($ this ->right instanceof self) && ($ this ->right ->information & ~3 ) == 0
594- ) {
595- return $ this ->decBalance ();
596- }
644+ return $ this ;
645+ }
646+
647+ /**
648+ * Remove from right subtree
649+ *
650+ * @param mixed $key The key
651+ * @param callable $comparator The comparator function
652+ *
653+ * @return TreeNode|null The new root
654+ *
655+ * @since 1.0.0
656+ */
657+ private function removeFromRight ($ key , $ comparator )
658+ {
659+ if ($ this ->information & 1 ) {
660+ $ right = $ this ->right ;
661+
662+ if (!$ right instanceof self) {
663+ return $ this ;
597664 }
598- } else {
599- if ($ this ->information & 1 ) {
600- $ right = $ this ->right ;
601665
602- if (!$ right instanceof self) {
603- return $ this ;
604- }
666+ $ rightBalance = $ right ->information & ~3 ;
667+ $ this ->right = $ right ->remove ($ key , $ comparator );
605668
606- $ rightBalance = $ right ->information & ~3 ;
607- $ this ->right = $ right ->pullUpLeftMost ();
669+ if (
670+ !($ this ->information & 1 )
671+ || $ rightBalance != 0 && ($ this ->right instanceof self) && ($ this ->right ->information & ~3 ) == 0
672+ ) {
673+ return $ this ->decBalance ();
674+ }
675+ }
608676
609- if (
610- !($ this ->information & 1 )
611- || $ rightBalance != 0 && ($ this ->right instanceof self) && ($ this ->right ->information & ~3 ) == 0
612- ) {
613- return $ this ->decBalance ();
614- }
615- } else {
616- $ left = $ this ->left ;
617- $ right = $ this ->right ;
677+ return $ this ;
678+ }
618679
619- if ($ this ->information & 2 ) {
620- $ left ->right = $ right ;
680+ /**
681+ * Remove current node key
682+ *
683+ * @return TreeNode|null The new root
684+ *
685+ * @since 1.0.0
686+ */
687+ private function removeCurrent ()
688+ {
689+ if ($ this ->information & 1 ) {
690+ $ right = $ this ->right ;
621691
622- return $ left ;
623- } else {
624- if ($ left && $ left ->right == $ this ) {
625- $ left ->information &= ~ 1 ;
692+ if (!$ right instanceof self) {
693+ return $ this ;
694+ }
626695
627- return $ right ;
628- } elseif ($ right && $ right ->left == $ this ) {
629- $ right ->information &= ~ 2 ;
696+ $ rightBalance = $ right ->information & ~3 ;
697+ $ this ->right = $ right ->pullUpLeftMost ();
630698
631- return $ left ;
632- } else {
633- return null ;
634- }
635- }
699+ if (
700+ !( $ this -> information & 1 )
701+ || $ rightBalance != 0 && ( $ this -> right instanceof self) && ( $ this -> right -> information & ~ 3 ) == 0
702+ ) {
703+ return $ this -> decBalance ();
636704 }
705+
706+ return $ this ;
637707 }
638708
639- return $ this ;
709+ $ left = $ this ->left ;
710+ $ right = $ this ->right ;
711+
712+ if ($ this ->information & 2 ) {
713+ $ left ->right = $ right ;
714+
715+ return $ left ;
716+ }
717+
718+ if ($ left && $ left ->right == $ this ) {
719+ $ left ->information &= ~ 1 ;
720+
721+ return $ right ;
722+ }
723+
724+ if ($ right && $ right ->left == $ this ) {
725+ $ right ->information &= ~ 2 ;
726+
727+ return $ left ;
728+ }
729+
730+ return null ;
640731 }
641732}
0 commit comments