Issues (15)

src/AVLTree.php (6 issues)

Labels
1
<?php
2
declare(strict_types=1);
3
/*
4
 * Copyright (C) 2019 Sebastian Böttger <[email protected]>
5
 * You may use, distribute and modify this code under the
6
 * terms of the MIT license.
7
 *
8
 * You should have received a copy of the MIT license with
9
 * this file. If not, please visit: https://opensource.org/licenses/mit-license.php
10
 */
11
12
namespace Seboettg\Forest;
13
14
use Seboettg\Forest\BinaryTree\BinaryNode;
15
use Seboettg\Forest\BinaryTree\BinaryNodeInterface;
16
use Seboettg\Forest\Item\ItemInterface;
17
18
/**
19
 * Class AVLTree
20
 *
21
 * @package Seboettg\Forest\AVLTree
22
 */
23
class AVLTree extends BinaryTree
24
{
25 14
    protected function insertItem($value): void
26
    {
27 14
        if ($this->root === null) {
28 14
            $this->root = new BinaryNode($value);
29
        } else {
30 14
            $this->root = $this->insertNode($this->root, $value);
31
        }
32 14
    }
33
34
    /**
35
     * @param BinaryNodeInterface $node
36
     * @param ItemInterface $item
37
     * @return BinaryNode|BinaryNodeInterface
38
     */
39 14
    final protected function insertNode(?BinaryNodeInterface $node, ItemInterface $item): BinaryNodeInterface
40
    {
41 14
        if (null === $node) {
42 14
            return new BinaryNode($item);
43
        }
44 14
        if ($item->compareTo($node->getItem()) < 0) {
0 ignored issues
show
It seems like $node->getItem() can also be of type null; however, parameter $b of Seboettg\Forest\Item\ItemInterface::compareTo() does only seem to accept Seboettg\Collection\Comparable\Comparable, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

44
        if ($item->compareTo(/** @scrutinizer ignore-type */ $node->getItem()) < 0) {
Loading history...
45 11
            $node->setLeft($this->insertNode($node->getLeft(), $item));
46
        } else {
47 13
            if ($item->compareTo($node->getItem()) > 0) {
48 13
                $node->setRight($this->insertNode($node->getRight(), $item));
49
            } else {
50
                return $node;
51
            }
52
        }
53
54 14
        if ($this->getBalance($node) > 1 && $item->compareTo($node->getLeft()->getItem()) < 0) {
55 10
            return $this->rotateRight($node);
56
        }
57 14
        $this->rebalance($item, $node);
58 14
        return $node;
59
    }
60
61
    /**
62
     * @param BinaryNodeInterface|null $node
63
     * @return int
64
     */
65 14
    protected function getBalance(?BinaryNodeInterface $node): int
66
    {
67 14
        $balanceLeft = null !== $node->getLeft() ? $node->getLeft()->getHeight() : 0;
0 ignored issues
show
The method getLeft() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

67
        $balanceLeft = null !== $node->/** @scrutinizer ignore-call */ getLeft() ? $node->getLeft()->getHeight() : 0;

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
68 14
        $balanceRight = null !== $node->getRight() ? $node->getRight()->getHeight() : 0;
69 14
        return $balanceLeft - $balanceRight;
70
    }
71
72
    /**
73
     * @param BinaryNodeInterface $node
74
     * @return BinaryNodeInterface
75
     */
76 13
    final private function rotateLeft(BinaryNodeInterface $node): BinaryNodeInterface
77
    {
78 13
        $tmp = $node->getRight();
79 13
        $node->setRight($node->getRight()->getLeft());
80 13
        $tmp->setLeft($node);
81 13
        return $tmp;
82
    }
83
84
    /**
85
     * @param BinaryNodeInterface $node
86
     * @return BinaryNodeInterface
87
     */
88 10
    final private function rotateRight(BinaryNodeInterface $node): BinaryNodeInterface
89
    {
90 10
        $tmp = $node->getLeft();
91 10
        $node->setLeft($node->getLeft()->getRight());
92 10
        $tmp->setRight($node);
93 10
        return $tmp;
94
    }
95
96
    /**
97
     * @param ItemInterface $item
98
     * @param BinaryNodeInterface|null $node
99
     */
100 7
    protected function removeItemRecursive(ItemInterface $item, ?BinaryNodeInterface &$node = null): void
101
    {
102 7
        parent::removeItemRecursive($item, $node);
103 7
        $this->rebalance($item, $node);
104 7
    }
105
106
    /**
107
     * @param BinaryNodeInterface $node
108
     */
109 7
    protected function reassignSubtree(BinaryNodeInterface &$node): void
110
    {
111 7
        if (empty($node->getLeft()) && empty($node->getRight())) { //no children?
112 4
            $node = null; // just unset the node and return
113 4
            return;
114
        }
115 5
        if (empty($node->getRight())) { // is there something on the right?
116 3
            $tmp = $node->getLeft(); // if not, return left node
117 3
            $tmp->setParent(null);
118 3
            $node = $tmp;
119
        } else {
120 4
            if (empty($node->getLeft())) { // is there something on the left?
121
                $tmp = $node->getRight(); // if not, return right node
122
                $tmp->setParent(null);
123
                $node = $tmp;
124
            } else { // left and right?
125 4
                $tmp = $node->getRight(); //keep right in mind
126 4
                $this->rebalance($node->getItem(), $tmp);
0 ignored issues
show
It seems like $node->getItem() can also be of type null; however, parameter $item of Seboettg\Forest\AVLTree::rebalance() does only seem to accept Seboettg\Forest\Item\ItemInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

126
                $this->rebalance(/** @scrutinizer ignore-type */ $node->getItem(), $tmp);
Loading history...
127 4
                $leftMostLeaf = $this->getLeftMostLeaf($tmp); // get the leftmost leaf of the right subtree
128 4
                $leftMostLeaf->setLeft($node->getLeft());  // append the left subtree to the leftmost leaf of the right subtree
129 4
                $node = $tmp;
130
            }
131
        }
132
133 5
    }
134
135
    /**
136
     * @param ItemInterface $item
137
     * @param BinaryNodeInterface|null $node
138
     */
139 14
    protected function rebalance(ItemInterface $item, ?BinaryNodeInterface &$node): void
140
    {
141 14
        $balance = $this->getBalance($node);
142 14
        if ($balance > 1) {
143
            // left left
144 1
            if ($item->compareTo($node->getLeft()->getItem()) < 0) {
0 ignored issues
show
It seems like $node->getLeft()->getItem() can also be of type null; however, parameter $b of Seboettg\Forest\Item\ItemInterface::compareTo() does only seem to accept Seboettg\Collection\Comparable\Comparable, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

144
            if ($item->compareTo(/** @scrutinizer ignore-type */ $node->getLeft()->getItem()) < 0) {
Loading history...
145 1
                $node = $this->rotateRight($node);
0 ignored issues
show
It seems like $node can also be of type null; however, parameter $node of Seboettg\Forest\AVLTree::rotateRight() does only seem to accept Seboettg\Forest\BinaryTree\BinaryNodeInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

145
                $node = $this->rotateRight(/** @scrutinizer ignore-type */ $node);
Loading history...
146
            }
147
            // left right
148 1
            if ($item->compareTo($node->getLeft()->getItem()) > 0) {
149 1
                $node->setLeft($this->rotateLeft($node->getLeft()));
150 1
                $node = $this->rotateRight($node);
151
            }
152
        }
153 14
        if ($balance < -1) {
154
            // right right
155 13
            if ($item->compareTo($node->getRight()->getItem()) > 0) {
156 8
                $node = $this->rotateLeft($node);
0 ignored issues
show
It seems like $node can also be of type null; however, parameter $node of Seboettg\Forest\AVLTree::rotateLeft() does only seem to accept Seboettg\Forest\BinaryTree\BinaryNodeInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

156
                $node = $this->rotateLeft(/** @scrutinizer ignore-type */ $node);
Loading history...
157
            }
158
            // right left
159 13
            if ($item->compareTo($node->getRight()->getItem()) < 0) {
160 9
                $node->setRight($this->rotateRight($node->getRight()));
161 9
                $node = $this->rotateLeft($node);
162
            }
163
        }
164 14
    }
165
}
166