Completed
Push — master ( 46289f...c51b27 )
by Siro Díaz
01:28
created

CircularLinkedList::shift()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
c 0
b 0
f 0
rs 10
cc 1
eloc 2
nc 1
nop 0
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\Lists;
10
11
use DataStructures\Lists\Traits\{CountTrait, ArrayAccessTrait};
12
use DataStructures\Lists\Nodes\SimpleLinkedListNode;
13
use DataStructures\Lists\ListAbstract;
14
use OutOfBoundsException;
15
16
/**
17
 * CircularLinkedList
18
 *
19
 * CircularLinkedList is a single and circular linked list that has
20
 * a pointer to the next node and also and last node points to head.
21
 *
22
 * @author Siro Diaz Palazon <[email protected]>
23
 */
24
class CircularLinkedList extends ListAbstract {
25
    use ArrayAccessTrait;
26
    private $head;
27
    private $tail;
28
    private $current;
29
    private $position;
30
31 View Code Duplication
    public function __construct() {
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...
32
        $this->head = null;
33
        $this->tail = &$this->head;
34
        $this->size = 0;
35
        $this->position = 0;
36
        $this->current = &$this->head;
37
    }
38
39
    /**
40
     * Inserts data in the specified position.
41
     *
42
     * @param integer $index the position.
43
     * @param mixed $data the data to store.
44
     */
45 View Code Duplication
    public function insert($index, $data) {
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...
46
        if($index < 0) {
47
            throw new OutOfBoundsException();
48
        }
49
50
        if($index === 0) {
51
            $this->insertBeginning($data);
52
        } else if($index >= $this->size) {
53
            $this->insertEnd($data);
54
        } else if($index > 0 && $index < $this->size) {
55
            $this->insertAt($index, $data);
56
        }
57
        $this->current = &$this->head;
58
        $this->size++;
59
    }
60
61
    /**
62
     * Inserts at the beginning of the list.
63
     *
64
     * @param mixed $data
65
     */
66
    private function insertBeginning($data) {
67
        $newNode = new SimpleLinkedListNode($data);
68
        if($this->head === null) {
69
            $newNode->next = &$this->head;
70
            $this->head = &$newNode;
71
            $this->tail = &$newNode;
72
        } else {
73
            $this->tail->next = &$newNode;
74
            $newNode->next = $this->head;
75
            $this->head = &$newNode;
76
        }
77
    }
78
79
    /**
80
     * Add a new node in the specified index.
81
     *
82
     * @param integer $index the position.
0 ignored issues
show
Bug introduced by
There is no parameter named $index. 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...
83
     * @param mixed $data the data to be stored.
84
     */
85
    private function insertEnd($data) {
86
        $newNode = new SimpleLinkedListNode($data);
87
        $this->tail->next = &$newNode;
88
        $newNode->next = &$this->head;
89
        $this->tail = &$newNode;
90
    }
91
92
    /**
93
     * Add a new node in the specified index.
94
     *
95
     * @param integer $index the position.
96
     * @param mixed $data the data to be stored.
97
     */
98
    private function insertAt($index, $data) {
99
        $newNode = new SimpleLinkedListNode($data);
100
        $current = $this->head;
101
        $prev = null;
102
        $i = 0;
103
        while($i < $index) {
104
            $prev = $current;
105
            $current = $current->next;
106
            $i++;
107
        }
108
        
109
        $prev->next = &$newNode;
110
        $newNode->next = &$current;
111
    }
112
113
    /**
114
     * Returns the last node data with O(1).
115
     *
116
     * @return mixed null if the list is empty.
117
     */
118
    public function getLast() {
119
        $node = $this->searchLast();
120
121
        return $node !== null ? $node->data : null;
122
    }
123
124
    /**
125
     * Returns the last node with O(1).
126
     *
127
     * @return mixed null if the list is empty.
128
     */
129
    protected function searchLast() {
130
        if($this->head === null) {
131
            return null;
132
        }
133
134
        return $this->tail;
135
    }
136
    
137
    /**
138
     * Returns the data stored in the given position.
139
     * If index is 0 or size - 1 the method is O(1) else O(n).
140
     *
141
     * @param integer $index the position.
142
     * @throws OutOfBoundsException if it is out of limits (< 0 or > size - 1)
143
     * @return mixed the data stored in $index node.
144
     */
145 View Code Duplication
    public function get($index) {
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...
146
        $node = $this->search($index);
147
        if($node === null) {
148
            return null;
149
        }
150
151
        return $node->data;
152
    }
153
154
    /**
155
     * Returns the node stored in the given position.
156
     * If index is 0 or (size - 1) the method is O(1) else O(n).
157
     *
158
     * @param integer $index the position.
159
     * @throws OutOfBoundsException if it is out of limits (< 0 or > size - 1)
160
     * @return DataStructures\Lists\Nodes\SimpleLinkedListNode the node stored in $index.
161
     */
162
    protected function search($index) {
163
        if($index < 0 || $index > $this->size - 1) {
164
            throw new OutOfBoundsException();
165
        }
166
167
        if($index === 0) {
168
            return $this->head;
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->head; of type null|DataStructures\List...es\SimpleLinkedListNode adds the type DataStructures\Lists\Nodes\SimpleLinkedListNode to the return on line 168 which is incompatible with the return type documented by DataStructures\Lists\CircularLinkedList::search of type DataStructures\Lists\Dat...es\SimpleLinkedListNode.
Loading history...
169
        }
170
171
        if($index === $this->size - 1) {
172
            return $this->searchLast();
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->searchLast(); of type null|DataStructures\List...es\SimpleLinkedListNode adds the type DataStructures\Lists\Nodes\SimpleLinkedListNode to the return on line 172 which is incompatible with the return type documented by DataStructures\Lists\CircularLinkedList::search of type DataStructures\Lists\Dat...es\SimpleLinkedListNode.
Loading history...
173
        }
174
175
        $i = 0;
176
        $current = $this->head;
177
        while($i < $index) {
178
            $current = $current->next;
179
            $i++;
180
        }
181
182
        return $current;
183
    }
184
185
    /**
186
     * {@inheritDoc}
187
     */
188
    public function contains($data) : bool {
189
        if($this->size === 0) {
190
            return false;
191
        }
192
193
        $current = $this->head->next;
194
        $prev = $this->head;
195
        while($current !== $this->head) {
196
            if($prev->data === $data) {
197
                return true;
198
            }
199
            
200
            $prev = $current;
201
            $current = $current->next;
202
        }
203
204
        if($prev->data === $data) {
205
            return true;
206
        }
207
208
        return false;
209
    }
210
211
    /**
212
     * {@inheritDoc}
213
     */
214 View Code Duplication
    public function indexOf($data) {
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...
215
        if($this->head === null) {
216
            return false;
217
        }
218
        
219
        $current = $this->head;
220
        $i = 0;
221
        
222
        while($i < $this->size) {
223
            if($current->data === $data) {
224
                return $i;
225
            }
226
227
            $current = $current->next;
228
            $i++;
229
        }
230
231
        return false;
232
    }
233
234
    /**
235
     * {@inheritDoc}
236
     */
237 View Code Duplication
    public function lastIndexOf($data) {
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...
238
        if($this->head === null) {
239
            return false;
240
        }
241
        
242
        $current = $this->head;
243
        $i = 0;
244
        $pos = false;
245
        while($i < $this->size) {
246
            if($current->data === $data) {
247
                $pos = $i;
248
            }
249
250
            $current = $current->next;
251
            $i++;
252
        }
253
        
254
        return $pos;
255
    }
256
257
    /**
258
     * {@inheritDoc}
259
     */
260
    public function remove($data) {
261
        $current = $this->head;
262
        $prev = $this->tail;
263
        $i = 0;
264
        
265
        if($this->head === null) {
266
            return null;
267
        }
268
269
        if($this->head->data === $data) {
270
            $this->head = &$this->head->next;
271
            $this->tail->next = &$this->head;
272
            $this->size--;
273
            return $current->data;
274
        }
275 View Code Duplication
        while($i < $this->size) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
276
            if($prev->data === $data) {
277
                $prev->next = &$current->next;
278
                $this->size--;
279
280
                return $current->data;
281
            }
282
283
            $prev = $current;
284
            $current = $current->next;
285
        }
286
287
        return null;
288
    }
289
290
    /**
291
     * Generator for retrieve all nodes stored.
292
     * 
293
     * @return null if the head is null (or list is empty)
294
     */
295 View Code Duplication
    public function getAll() {
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...
296
        if($this->head === null) {
297
            return;
298
        }
299
        
300
        if($this->head->next === $this->tail) {
301
            yield $this->head->data;
302
        } else {
303
            $current = $this->head;
304
            $i = 0;
305
            while($i < $this->size) {
306
                yield $current->data;
307
                $current = $current->next;
308
                $i++;
309
            }
310
        }
311
    }
312
    
313
    /**
314
     * Delete a node in the given position and returns it back.
315
     *
316
     * @param integer $index the position.
317
     * @throws OutOfBoundsException if index is negative
318
     *  or is greater than the size of the list.
319
     */
320 View Code Duplication
    public function delete($index) {
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...
321
        if($index < 0 || ($index > 0 && $index > $this->size - 1)) {
322
            throw new OutOfBoundsException();
323
        }
324
325
        // if the list is empty
326
        if($this->head === null) {
327
            return null;
328
        }
329
        
330
        // if only there is an element
331
        if($this->head->next === $this->head) {
332
            $temp = $this->head;
333
            $this->head = null;
334
            $this->size--;
335
336
            return $temp->data;
337
        }
338
339
        if($index === 0) {
340
            return $this->deleteBeginning();
341
        } else if($index === $this->size - 1) {
342
            return $this->deleteEnd();
343
        } else {
344
            return $this->deleteAt($index);
345
        }
346
    }
347
348
    /**
349
     * Deletes at the beginnig of the list and returns the data stored.
350
     *
351
     * @return mixed the data stored in the node.
352
     */
353 View Code Duplication
    private function deleteBeginning() {
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...
354
        $temp = $this->head;
355
        $this->head = &$this->head->next;
356
        $this->tail->next = &$this->head;
357
        $this->size--;
358
359
        return $temp->data;
360
    }
361
362
    /**
363
     * Deletes at the specified position and returns the data stored.
364
     *
365
     * @param integer $index the position.
366
     * @return mixed the data stored in the node.
367
     */
368
    private function deleteAt($index) {
369
        $i = 0;
370
        $prev = $this->head;
371
        $current = $this->head;
372
        
373
        while($i < $index) {
374
            $prev = $current;
375
            $current = $current->next;
376
            $i++;
377
        }
378
379
        $prev->next = &$current->next;
380
        $this->size--;
381
382
        return $current->data;
383
    }
384
385
    /**
386
     * Deletes at the end of the list and returns the data stored.
387
     *
388
     * @return mixed the data stored in the node.
389
     */
390 View Code Duplication
    private function deleteEnd() {
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...
391
        $prev = $this->head;
392
        $current = $this->head;
393
        
394
        while($current !== $this->tail) {
395
            $prev = $current;
396
            $current = $current->next;
397
        }
398
        
399
        $temp = $current;
400
        $prev->next = &$this->head;
401
        $this->tail = &$prev;
402
        $current = null;
0 ignored issues
show
Unused Code introduced by
$current is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
403
404
        $this->size--;
405
406
        return $temp->data;
407
    }
408
409
    /**
410
     * Removes all nodes of the list. It removes from the beginning.
411
     */
412
    public function clear() {
413
        while($this->head !== null) {
414
            $this->shift();
415
        }
416
    }
417
418
    /**
419
     * Converts/exports the list content into array type.
420
     *
421
     * @return array data stored in all nodes.
422
     */
423
    public function toArray() : array {
424
        $arr = [];
425
        foreach($this->getAll() as $node) {
426
            $arr[] = $node;
427
        }
428
429
        return $arr;
430
    }
431
432
    /**
433
     * Reset the cursor position.
434
     */
435
    public function rewind() {
436
        $this->position = 0;
437
        $this->current = &$this->head;
438
    }
439
440
    /**
441
     * Returns the current node data.
442
     *
443
     * @return mixed
444
     */
445
    public function current() {
446
        return $this->current->data;
447
    }
448
449
    /**
450
     * Key or index that indicates the cursor position.
451
     *
452
     * @return integer The current position.
453
     */
454
    public function key() {
455
        return $this->position;
456
    }
457
458
    /**
459
     * Move the cursor to the next node and increments the
460
     * position counter.
461
     */
462
    public function next() {
463
        ++$this->position;
464
        $this->current = $this->current->next;
465
    }
466
467
    /**
468
     * Returns if the current pointer position is valid.
469
     *
470
     * @return boolean true if pointer is not last, else false.
471
     */
472
    public function valid() {
473
        return $this->position < $this->size;
474
    }
475
}