Completed
Push — master ( b592b0...7a2d4e )
by Siro Díaz
02:02
created

BinarySearchTree::get()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 22
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 22
rs 8.6737
cc 6
eloc 14
nc 8
nop 1
1
<?php
2
/**
3
 * DataStructures for PHP
4
 *
5
 * @link      https://github.com/SiroDiaz/DataStructures
6
 * @copyright Copyright (c) 2017 Siro Díaz Palazón
7
 * @license   https://github.com/SiroDiaz/DataStructures/blob/master/README.md (MIT License)
8
 */
9
namespace DataStructures\Trees;
10
11
use DataStructures\Trees\Nodes\BSTNode;
12
use DataStructures\Trees\Interfaces\BinaryNodeInterface;
13
use DataStructures\Trees\BinaryTreeAbstract;
14
15
/**
16
 * BinarySearchTree
17
 * 
18
 * Represents a BST actions that can be realized.
19
 * At the beginning root is null and it can grow up to a O(n) in search,
20
 * delete and insert (in worst case). In best cases it will be O(log n).
21
 *
22
 * @author Siro Diaz Palazon <[email protected]>
23
 */
24
class BinarySearchTree extends BinaryTreeAbstract {
25
26
    public function __construct() {
27
        $this->root = null;
28
        $this->size = 0;
29
    }
30
31
    /**
32
     * Inserts data in the correct position.
33
     *
34
     * @param integer|string $key the key used to store.
35
     * @param mixed $data the data to store.
36
     * @param bool $update if false the node isn't updated
37
     *  else if the key matches is updated.
38
     */
39
    public function put($key, $data, $update = false) {
40
        $newNode = new BSTNode($key, $data);
41
        
42
        if($this->root === null) {
43
            $this->root = &$newNode;
44
            $this->size++;
45
            return;
46
        }
47
48
        $parentNode = null;
49
        $current = &$this->root;
50
        while($current !== null) {
51
            $parentNode = &$current;
52
            if($key < $current->key) {
53
                $current = &$current->left;
54
            } else if($key > $current->key) {
55
                $current = &$current->right;
56
            } else {
57
                if($update) {
58
                    $current->data = $data;
59
                }
60
                return;
61
            }
62
        }
63
64
        $newNode->parent = &$parentNode;
65
        if($key < $parentNode->key) {
66
            $parentNode->left = &$newNode;
67
        } else {
68
            $parentNode->right = &$newNode;
69
        }
70
71
        $this->size++;
72
    }
73
    
74
    /**
75
     * Creates a new node or updates it if already exists.
76
     *
77
     * @param int|string $key the key.
78
     * @param mixed $data the data to be stored. 
79
     */
80
    public function putOrUpdate($key, $data) {
81
        $this->put($key, $data, true);
82
    }
83
84
    /**
85
     * Deletes the node with the maximum key and returns it. The most right and more bottom.
86
     * 
87
     * @param DataStructures\Trees\Nodes\BSTNode|null if null takes the root.
88
     * @return DataStructures\Trees\Nodes\BSTNode|null the maximum node or
89
     *  null if the tree is empty.
90
     */
91
    public function delete($key) {
92
        $deleteNode = $this->search($key);
93
        if($deleteNode !== null) {
94
            $this->_delete($deleteNode);
95
            return $deleteNode;
96
        }
97
98
        return null;
99
    }
100
101
    /**
102
     * Deletes the selected node if is not null and returns the node
103
     * that replaces the deleted node. Also decrease the size of tree.
104
     *
105
     * @param DataStructures\Trees\Nodes\BSTNode|null The node to be deleted.
106
     * @return the node that replaces the deleted.
107
     */
108
    protected function _delete(BinaryNodeInterface &$node) {
109
        if($node !== null) {
110
            $nodeToReturn = null;
111
            if($node->left === null) {
0 ignored issues
show
Bug introduced by
Accessing left on the interface DataStructures\Trees\Int...ces\BinaryNodeInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
112
                $nodeToReturn = $this->replace($node, $node->right);
0 ignored issues
show
Bug introduced by
Accessing right on the interface DataStructures\Trees\Int...ces\BinaryNodeInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Documentation introduced by
$node is of type object<DataStructures\Tr...es\BinaryNodeInterface>, but the function expects a object<DataStructures\Tr...es\Trees\Nodes\BSTNode>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug Compatibility introduced by
The expression $this->replace($node, $node->right); of type DataStructures\Trees\Dat...rees\Nodes\BSTNode|null adds the type DataStructures\Trees\Dat...res\Trees\Nodes\BSTNode to the return on line 130 which is incompatible with the return type declared by the abstract method DataStructures\Trees\BinaryTreeAbstract::_delete of type DataStructures\Trees\the.
Loading history...
113
            } else if($node->right === null) {
0 ignored issues
show
Bug introduced by
Accessing right on the interface DataStructures\Trees\Int...ces\BinaryNodeInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
114
                $nodeToReturn = $this->replace($node, $node->left);
0 ignored issues
show
Bug introduced by
Accessing left on the interface DataStructures\Trees\Int...ces\BinaryNodeInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Documentation introduced by
$node is of type object<DataStructures\Tr...es\BinaryNodeInterface>, but the function expects a object<DataStructures\Tr...es\Trees\Nodes\BSTNode>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug Compatibility introduced by
The expression $this->replace($node, $node->left); of type DataStructures\Trees\Dat...rees\Nodes\BSTNode|null adds the type DataStructures\Trees\Dat...res\Trees\Nodes\BSTNode to the return on line 130 which is incompatible with the return type declared by the abstract method DataStructures\Trees\BinaryTreeAbstract::_delete of type DataStructures\Trees\the.
Loading history...
115
            } else {
116
                $successorNode = $this->getMinNode($node->right);
0 ignored issues
show
Bug introduced by
The method getMinNode() cannot be called from this context as it is declared private in class DataStructures\Trees\BinaryTreeAbstract.

This check looks for access to methods that are not accessible from the current context.

If you need to make a method accessible to another context you can raise its visibility level in the defining class.

Loading history...
Bug introduced by
Accessing right on the interface DataStructures\Trees\Int...ces\BinaryNodeInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Bug Compatibility introduced by
The expression $this->getMinNode($node->right); of type DataStructures\Trees\Dat...rees\Nodes\BSTNode|null adds the type DataStructures\Trees\Dat...res\Trees\Nodes\BSTNode to the return on line 130 which is incompatible with the return type declared by the abstract method DataStructures\Trees\BinaryTreeAbstract::_delete of type DataStructures\Trees\the.
Loading history...
117
                if($successorNode->parent !== $node) {
118
                    $this->replace($successorNode, $successorNode->right);
119
                    $successorNode->right = &$node->right;
0 ignored issues
show
Bug introduced by
Accessing right on the interface DataStructures\Trees\Int...ces\BinaryNodeInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
120
                    $successorNode->right->parent = &$successorNode;
121
                }
122
123
                $this->replace($node, $successorNode);
124
                $successorNode->left = &$node->left;
125
                $successorNode->left->parent = &$successorNode;
126
                $nodeToReturn = &$successorNode;
127
            }
128
129
            $this->size--;
130
            return $nodeToReturn;
131
        }
132
133
        return null;
134
    }
135
136
    /**
137
     * Traverse in preorder. This is: first visit the root, then
138
     * the left subtree and finally the right subtree.
139
     *
140
     * @param Callable|null $callback the callback function to apply to each
141
     *  node.
142
     */
143
    public function preorder(Callable $callback = null) {
144
        $this->_preorder($this->root, $callback);
145
    }
146
147
    /**
148
     * Private preorder traverse method that is recursive and is called by
149
     * the public preorder method.
150
     *
151
     * @param DataStructures\Trees\Nodes\BSTNode|null $node.
0 ignored issues
show
Bug introduced by
There is no parameter named $node.. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
152
     * @param Callable|null $callback the callback function to apply to each
153
     *  node.
154
     */
155 View Code Duplication
    private function _preorder($node, Callable $callback = null) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
156
        if($node === null) {
157
            return;
158
        }
159
        if($callback !== null) {
160
            call_user_func($callback, $node);
161
        }
162
        $this->_preorder($node->left, $callback);
163
        $this->_preorder($node->right, $callback);
164
    }
165
166
    /**
167
     * Traverse in inorder. This is: first visit the left subtree,
168
     * then the root and finally the right subtree.
169
     *
170
     * @param Callable|null $callback the callback function to apply to each
171
     *  node.
172
     */
173
    public function inorder(Callable $callback = null) {
0 ignored issues
show
Unused Code introduced by
The parameter $callback is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
174
        $this->_inorder($this->root);
175
    }
176
177
    /**
178
     * Private inorder traverse method that is recursive and is called by
179
     * the public inorder method.
180
     *
181
     * @param DataStructures\Trees\Nodes\BSTNode|null $node.
0 ignored issues
show
Bug introduced by
There is no parameter named $node.. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
182
     * @param Callable|null $callback the callback function to apply to each
183
     *  node.
184
     */
185 View Code Duplication
    private function _inorder($node, Callable $callback = null) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
186
        if($node === null) {
187
            return;
188
        }
189
190
        $this->_inorder($node->left, $callback);
191
        if($callback !== null) {
192
            call_user_func($callback, $node);
193
        }
194
        $this->_inorder($node->right, $callback);
195
    }
196
197
    /**
198
     * Traverse in postorder. This is: first visit the left subtree,
199
     * then the right subtree and finally the root.
200
     *
201
     * @param Callable|null $callback the callback function to apply to each
202
     *  node.
203
     */
204
    public function postorder(Callable $callback = null) {
205
        $this->_postorder($this->root, $callback);
206
    }
207
208
    /**
209
     * Private postorder traverse method that is recursive and is called by
210
     * the public postorder method.
211
     *
212
     * @param DataStructures\Trees\Nodes\BSTNode|null $node.
0 ignored issues
show
Bug introduced by
There is no parameter named $node.. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
213
     * @param Callable|null $callback the callback function to apply to each
214
     *  node.
215
     */
216 View Code Duplication
    private function _postorder($node, Callable $callback = null) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
217
        if($node === null) {
218
            return;
219
        }
220
        $this->_postorder($node->left, $callback);
221
        $this->_postorder($node->right, $callback);
222
        if($callback !== null) {
223
            call_user_func($callback, $node);
224
        }
225
    }
226
}