Completed
Push — master ( 2cb83b...930afd )
by Siro Díaz
01:41
created

CircularLinkedList::remove()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 11

Duplication

Lines 17
Ratio 100 %

Importance

Changes 0
Metric Value
dl 17
loc 17
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 11
nc 3
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\Lists;
10
11
use DataStructures\Lists\Traits\{CountTrait, ArrayAccessTrait};
12
use DataStructures\Lists\Nodes\SimpleLinkedListNode;
13
use DataStructures\Lists\Interfaces\ListInterface;
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 implements ListInterface {
25
    use ArrayAccessTrait;
26
    private $head;
27
    private $tail;
28
    private $size;
29
    private $current;
30
    private $position;
31
32 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...
33
        $this->head = null;
34
        $this->tail = &$this->head;
35
        $this->size = 0;
36
        $this->position = 0;
37
        $this->current = &$this->head;
38
    }
39
40
    /**
41
     * Inserts data in the specified position.
42
     *
43
     * @param integer $index the position.
44
     * @param mixed $data the data to store.
45
     */
46 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...
47
        if($index < 0) {
48
            throw new OutOfBoundsException();
49
        }
50
51
        if($index === 0) {
52
            $this->insertBeginning($data);
53
        } else if($index >= $this->size) {
54
            $this->insertEnd($data);
55
        } else if($index > 0 && $index < $this->size) {
56
            $this->insertAt($index, $data);
57
        }
58
        $this->current = &$this->head;
59
        $this->size++;
60
    }
61
62
    /**
63
     * Inserts at the beginning of the list.
64
     *
65
     * @param mixed $data
66
     */
67
    private function insertBeginning($data) {
68
        $newNode = new SimpleLinkedListNode($data);
69
        if($this->head === null) {
70
            $newNode->next = &$this->head;
71
            $this->head = &$newNode;
72
            $this->tail = &$newNode;
73
        } else {
74
            $this->tail->next = &$newNode;
75
            $newNode->next = $this->head;
76
            $this->head = &$newNode;
77
        }
78
    }
79
80
    /**
81
     * Add a new node in the specified index.
82
     *
83
     * @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...
84
     * @param mixed $data the data to be stored.
85
     */
86
    private function insertEnd($data) {
87
        $newNode = new SimpleLinkedListNode($data);
88
        $this->tail->next = &$newNode;
89
        $newNode->next = &$this->head;
90
        $this->tail = &$newNode;
91
    }
92
93
    /**
94
     * Add a new node in the specified index.
95
     *
96
     * @param integer $index the position.
97
     * @param mixed $data the data to be stored.
98
     */
99
    private function insertAt($index, $data) {
100
        $newNode = new SimpleLinkedListNode($data);
101
        $current = $this->head;
102
        $prev = null;
103
        $i = 0;
104
        while($i < $index) {
105
            $prev = $current;
106
            $current = $current->next;
107
            $i++;
108
        }
109
        
110
        $prev->next = &$newNode;
111
        $newNode->next = &$current;
112
    }
113
114
    /**
115
     * Adds at the end of the list new node containing
116
     * the data to be stored.
117
     *
118
     * @param mixed $data The data
119
     */
120
    public function push($data) {
121
        $this->insert($this->size, $data);
122
    }
123
124
    /**
125
     * Adds at the beginning a node in the list.
126
     *
127
     * @param mixed $data
128
     * @return mixed the data stored.
129
     */
130
    public function unshift($data) {
131
        $this->insert(0, $data);
132
    }
133
134
    /**
135
     * Returns the last node data with O(1).
136
     *
137
     * @return mixed null if the list is empty.
138
     */
139
    public function getLast() {
140
        $node = $this->searchLast();
141
142
        return $node !== null ? $node->data : null;
143
    }
144
145
    /**
146
     * Returns the last node with O(1).
147
     *
148
     * @return mixed null if the list is empty.
149
     */
150
    protected function searchLast() {
151
        if($this->head === null) {
152
            return null;
153
        }
154
155
        return $this->tail;
156
    }
157
    
158
    /**
159
     * Returns the data stored in the given position.
160
     * If index is 0 or size - 1 the method is O(1) else O(n).
161
     *
162
     * @param integer $index the position.
163
     * @throws OutOfBoundsException if it is out of limits (< 0 or > size - 1)
164
     * @return mixed the data stored in $index node.
165
     */
166 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...
167
        $node = $this->search($index);
168
        if($node === null) {
169
            return null;
170
        }
171
172
        return $node->data;
173
    }
174
175
    /**
176
     * Returns the node stored in the given position.
177
     * If index is 0 or (size - 1) the method is O(1) else O(n).
178
     *
179
     * @param integer $index the position.
180
     * @throws OutOfBoundsException if it is out of limits (< 0 or > size - 1)
181
     * @return DataStructures\Lists\Nodes\SimpleLinkedListNode the node stored in $index.
182
     */
183
    protected function search($index) {
184
        if($index < 0 || $index > $this->size - 1) {
185
            throw new OutOfBoundsException();
186
        }
187
188
        if($index === 0) {
189
            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 189 which is incompatible with the return type documented by DataStructures\Lists\CircularLinkedList::search of type DataStructures\Lists\Dat...es\SimpleLinkedListNode.
Loading history...
190
        }
191
192
        if($index === $this->size - 1) {
193
            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 193 which is incompatible with the return type documented by DataStructures\Lists\CircularLinkedList::search of type DataStructures\Lists\Dat...es\SimpleLinkedListNode.
Loading history...
194
        }
195
196
        $i = 0;
197
        $current = $this->head;
198
        while($i < $index) {
199
            $current = $current->next;
200
            $i++;
201
        }
202
203
        return $current;
204
    }
205
206
    /**
207
     *
208
     */
209
    public function contains($data) : bool {
210
        if($this->size === 0) {
211
            return false;
212
        }
213
214
        $current = $this->head->next;
215
        $prev = $this->head;
216
        while($current !== $this->head) {
217
            if($prev->data === $data) {
218
                return true;
219
            }
220
            $prev = $current;
221
            $current = $current->next;
222
        }
223
224
        return false;
225
    }
226
227
    /**
228
     *
229
     */
230 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...
231
        if($this->head === null) {
232
            return false;
233
        }
234
        
235
        $current = $this->head;
236
        $i = 0;
237
        
238
        while($i < $this->size) {
239
            if($current->data == $data) {
240
                return $i;
241
            }
242
243
            $current = $current->next;
244
            $i++;
245
        }
246
247
        return false;
248
    }
249
250
    /**
251
     *
252
     */
253 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...
254
        if($this->head === null) {
255
            return false;
256
        }
257
        
258
        $current = $this->head;
259
        $i = 0;
260
        $pos = false;
261
        while($i < $this->size) {
262
            if($current->data == $data) {
263
                $pos = $i;
264
            }
265
266
            $current = $current->next;
267
            $i++;
268
        }
269
270
        return $pos;
271
    }
272
273
    /**
274
     *
275
     */
276 View Code Duplication
    public function remove($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...
277
        $current = $this->head;
278
        $prev = $this->tail;
279
        $i = 0;
280
        
281
        while($i < $this->size) {
282
            if($pev->data === $data) {
0 ignored issues
show
Bug introduced by
The variable $pev does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
283
                $prev->next = &$current->next;
284
                return $current->data;
285
            }
286
287
            $prev = $current;
288
            $current = $current->next;
289
        }
290
291
        return null;
292
    }
293
294
    /**
295
     * Generator for retrieve all nodes stored.
296
     * 
297
     * @return null if the head is null (or list is empty)
298
     */
299 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...
300
        if($this->head === null) {
301
            return;
302
        }
303
        
304
        if($this->head->next === $this->tail) {
305
            yield $this->head->data;
306
        } else {
307
            $current = $this->head;
308
            $i = 0;
309
            while($i < $this->size) {
310
                yield $current->data;
311
                $current = $current->next;
312
                $i++;
313
            }
314
        }
315
    }
316
    
317
    /**
318
     * Delete a node in the given position and returns it back.
319
     *
320
     * @param integer $index the position.
321
     * @throws OutOfBoundsException if index is negative
322
     *  or is greater than the size of the list.
323
     */
324 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...
325
        if($index < 0 || ($index > 0 && $index > $this->size - 1)) {
326
            throw new OutOfBoundsException();
327
        }
328
329
        // if the list is empty
330
        if($this->head === null) {
331
            return null;
332
        }
333
        
334
        // if only there is an element
335
        if($this->head->next === $this->head) {
336
            $temp = $this->head;
337
            $this->head = null;
338
            $this->size--;
339
340
            return $temp->data;
341
        }
342
343
        if($index === 0) {
344
            return $this->deleteBeginning();
345
        } else if($index === $this->size - 1) {
346
            return $this->deleteEnd();
347
        } else {
348
            return $this->deleteAt($index);
349
        }
350
    }
351
352
    /**
353
     * Deletes at the beginnig of the list and returns the data stored.
354
     *
355
     * @return mixed the data stored in the node.
356
     */
357 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...
358
        $temp = $this->head;
359
        $this->head = &$this->head->next;
360
        $this->tail->next = &$this->head;
361
        $this->size--;
362
363
        return $temp->data;
364
    }
365
366
    /**
367
     * Deletes at the specified position and returns the data stored.
368
     *
369
     * @param integer $index the position.
370
     * @return mixed the data stored in the node.
371
     */
372 View Code Duplication
    private function deleteAt($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...
373
        $i = 0;
374
        $prev = $this->head;
375
        $current = $this->head;
376
        
377
        while($i < $index) {
378
            $prev = $current;
379
            $current = $current->next;
380
            $i++;
381
        }
382
383
        $prev->next = &$current->next;
384
        $this->size--;
385
386
        return $current->data;
387
    }
388
389
    /**
390
     * Deletes at the end of the list and returns the data stored.
391
     *
392
     * @return mixed the data stored in the node.
393
     */
394 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...
395
        $prev = $this->head;
396
        $current = $this->head;
397
        
398
        while($current !== $this->tail) {
399
            $prev = $current;
400
            $current = $current->next;
401
        }
402
        
403
        $temp = $current;
404
        $prev->next = &$this->head;
405
        $this->tail = &$prev;
406
        $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...
407
408
        $this->size--;
409
410
        return $temp->data;
411
    }
412
413
    /**
414
     * Deletes the first node of the list and returns it.
415
     *
416
     * @return mixed the data.
417
     */
418
    public function shift() {
419
        return $this->delete(0);
420
    }
421
422
    /**
423
     * Removes and returns the last node in the list.
424
     *
425
     * @return mixed data in node.
426
     */
427
    public function pop() {
428
        return $this->delete($this->size - 1);
429
    }
430
431
    /**
432
     * Removes all nodes of the list. It removes from the beginning.
433
     */
434
    public function clear() {
435
        while($this->head !== null) {
436
            $this->shift();
437
        }
438
    }
439
440
    /**
441
     * Converts/exports the list content into array type.
442
     *
443
     * @return array data stored in all nodes.
444
     */
445
    public function toArray() : array {
446
        $arr = [];
447
        foreach($this->getAll() as $node) {
448
            $arr[] = $node;
449
        }
450
451
        return $arr;
452
    }
453
454
    /**
455
     * Reset the cursor position.
456
     */
457
    public function rewind() {
458
        $this->position = 0;
459
        $this->current = &$this->head;
460
    }
461
462
    /**
463
     * Returns the current node data.
464
     *
465
     * @return mixed
466
     */
467
    public function current() {
468
        return $this->current->data;
469
    }
470
471
    /**
472
     * Key or index that indicates the cursor position.
473
     *
474
     * @return integer The current position.
475
     */
476
    public function key() {
477
        return $this->position;
478
    }
479
480
    /**
481
     * Move the cursor to the next node and increments the
482
     * position counter.
483
     */
484
    public function next() {
485
        ++$this->position;
486
        $this->current = $this->current->next;
487
    }
488
489
    /**
490
     * Returns if the current pointer position is valid.
491
     *
492
     * @return boolean true if pointer is not last, else false.
493
     */
494
    public function valid() {
495
        return $this->position < $this->size;
496
    }
497
498
    /**
499
     * Binds to count() method. This is equal to make $this->tree->size().
500
     *
501
     * @return integer the tree size. 0 if it is empty.
502
     */
503
    public function count() {
504
        return $this->size;
505
    }
506
507
    /**
508
     * Returns the array size.
509
     *
510
     * @return int the length
511
     */
512
    public function size() : int {
513
        return $this->size;
514
    }
515
516
    /**
517
     * Checks if the list is empty.
518
     *
519
     * @return boolean true if is empty, else false.
520
     */
521
    public function empty() : bool {
522
        return $this->size === 0;
523
    }
524
}