Skip to content

Commit efb8099

Browse files
committed
minor refactoring, linked list iterator
1 parent 6d005dd commit efb8099

File tree

6 files changed

+181
-71
lines changed

6 files changed

+181
-71
lines changed

src/Common/Abstracts/AbstractLinkedList.php

+45-51
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,12 @@
2929
use doganoo\PHPAlgorithms\Common\Interfaces\IComparable;
3030
use doganoo\PHPAlgorithms\Common\Interfaces\INode;
3131
use doganoo\PHPAlgorithms\Common\Interfaces\IUnaryNode;
32+
use doganoo\PHPAlgorithms\Common\Iterator\LinkedListIterator;
3233
use doganoo\PHPAlgorithms\Common\Util\Comparator;
3334
use doganoo\PHPAlgorithms\Datastructure\Lists\Node;
35+
use IteratorAggregate;
3436
use JsonSerializable;
3537

36-
3738
/**
3839
* Class LinkedList
3940
*
@@ -46,7 +47,11 @@
4647
* Linked lists are a necessary data structure, since they give you dynamic memory allocation with less danger of buffer overruns. Which means you had to write linked lists by hand. Which means you had to manipulate the pointers in linked lists by hand.
4748
*
4849
*/
49-
abstract class AbstractLinkedList implements IComparable, JsonSerializable {
50+
abstract class AbstractLinkedList
51+
implements
52+
IComparable
53+
, JsonSerializable
54+
, IteratorAggregate {
5055

5156
/** @var Node */
5257
private $head = null;
@@ -75,17 +80,18 @@ abstract class AbstractLinkedList implements IComparable, JsonSerializable {
7580
* ================================
7681
* 5 -> 4 -> 3 -> 2 -> 1 -> NULL
7782
*/
78-
public function reverse() {
83+
public function reverse(): void {
84+
$current = $this->getHead();
7985
$prev = null;
8086
$next = null;
81-
$current = $this->getHead();
8287

8388
while ($current !== null) {
8489
$next = $current->getNext();
8590
$current->setNext($prev);
8691
$prev = $current;
8792
$current = $next;
8893
}
94+
8995
$this->setHead($prev);
9096
}
9197

@@ -103,7 +109,7 @@ public function getHead(): ?Node {
103109
*
104110
* @param Node|null $node
105111
*/
106-
public function setHead(?Node $node) {
112+
public function setHead(?Node $node): void {
107113
$this->head = $node;
108114
}
109115

@@ -148,12 +154,12 @@ public function deleteNode($data): bool {
148154
* head twice. If the list contains duplicates, the next-next is set
149155
* as the next node of the current node.
150156
*/
151-
public function removeDuplicates() {
157+
public function removeDuplicates(): void {
152158
$tortoise = $this->head;
153159

154-
while ($tortoise !== null) {
160+
while (null !== $tortoise) {
155161
$hare = $tortoise;
156-
while ($hare->getNext() !== null) {
162+
while (null !== $hare->getNext()) {
157163
if (Comparator::equals($hare->getNext()->getValue(), $tortoise->getValue())) {
158164
$hare->setNext($hare->getNext()->getNext());
159165
} else {
@@ -162,6 +168,7 @@ public function removeDuplicates() {
162168
}
163169
$tortoise = $tortoise->getNext();
164170
}
171+
165172
}
166173

167174
/**
@@ -183,11 +190,11 @@ public function removeDuplicates() {
183190
* @return AbstractLinkedList|null
184191
*
185192
*/
186-
public function getLastElements(int $number): AbstractLinkedList {
193+
public function getLastElements(int $number): ?AbstractLinkedList {
187194
$p1 = $this->getHead();
188195
$p2 = $this->getHead();
189196
$number = $number > $this->head->size() ? $this->head->size() : $number;
190-
$list = $this->getEmptyInstance();
197+
$list = new static();
191198

192199
for ($i = 0; $i < $number; $i++) {
193200
if ($p1 == null) {
@@ -208,22 +215,6 @@ public function getLastElements(int $number): AbstractLinkedList {
208215
return $list;
209216
}
210217

211-
/**
212-
* abstract method that requires inheritors to return their type
213-
*
214-
* @return AbstractLinkedList
215-
*/
216-
protected abstract function getEmptyInstance(): AbstractLinkedList;
217-
218-
/**
219-
* abstract method that requires inheritors to implement the way how
220-
* values are prepended to the list
221-
*
222-
* @param Node|null $node
223-
* @return bool
224-
*/
225-
public abstract function append(?Node $node): bool;
226-
227218
////This problem cannot be solved if the node to be deleted is
228219
////the last node in the linked list
229220
////node could be marked as dummy
@@ -254,7 +245,7 @@ public function getFirstElements(int $number): AbstractLinkedList {
254245
$head = $this->getHead();
255246
//if there are more elements requested than the list provides
256247
$number = $number > $head->size() ? $head->size() : $number;
257-
$list = $this->getEmptyInstance();
248+
$list = new static();
258249
$i = 0;
259250
while ($i < $number) {
260251
//TODO append or prepend?
@@ -265,6 +256,15 @@ public function getFirstElements(int $number): AbstractLinkedList {
265256
return $list;
266257
}
267258

259+
/**
260+
* abstract method that requires inheritors to implement the way how
261+
* values are prepended to the list
262+
*
263+
* @param Node|null $node
264+
* @return bool
265+
*/
266+
public abstract function append(?Node $node): bool;
267+
268268
/**
269269
* abstract method that requires inheritors to implement the way how
270270
* values are prepended to the list
@@ -423,7 +423,7 @@ public function remove($key): bool {
423423
* The while loop iterates over all nodes until the
424424
* value is found.
425425
*/
426-
while ($head !== null && Comparator::notEquals($head->getKey(), $key)) {
426+
while (null !== $head && Comparator::notEquals($head->getKey(), $key)) {
427427
/*
428428
* since a node is going to be removed from the
429429
* node chain, the previous element has to be
@@ -467,7 +467,7 @@ public function remove($key): bool {
467467
public function replaceValue($key, $value): bool {
468468
$replaced = false;
469469
$node = $this->getHead();
470-
while ($node !== null) {
470+
while (null !== $node) {
471471
if (Comparator::equals($node->getKey(), $key)) {
472472
$node->setValue($value);
473473
$replaced = true;
@@ -483,11 +483,11 @@ public function replaceValue($key, $value): bool {
483483
*/
484484
public function compareTo($object): int {
485485
if ($object instanceof AbstractLinkedList) {
486-
if (Comparator::equals($this->getHead(), $object->getHead())) return 0;
487-
if (Comparator::lessThan($this->getHead(), $object->getHead())) return -1;
488-
if (Comparator::greaterThan($this->getHead(), $object->getHead())) return 1;
486+
if (Comparator::equals($this->getHead(), $object->getHead())) return IComparable::EQUAL;
487+
if (Comparator::lessThan($this->getHead(), $object->getHead())) return IComparable::IS_LESS;
488+
if (Comparator::greaterThan($this->getHead(), $object->getHead())) return IComparable::IS_GREATER;
489489
}
490-
return -1;
490+
return IComparable::IS_LESS;
491491
}
492492

493493
/**
@@ -573,6 +573,9 @@ public function getIntersectionNode(AbstractLinkedList $list): ?INode {
573573

574574

575575
while (null !== $l1 && null !== $l2) {
576+
// we can not use the identity operator here
577+
// since it requires to be the exact same
578+
// instance!
576579
if ($l1 == $l2) {
577580
return $l1;
578581
}
@@ -589,7 +592,7 @@ public function getIntersectionNode(AbstractLinkedList $list): ?INode {
589592
* @return int
590593
*/
591594
public function size() {
592-
if ($this->isEmpty()) {
595+
if (true === $this->isEmpty()) {
593596
return 0;
594597
}
595598
return $this->head->size();
@@ -604,6 +607,13 @@ public function isEmpty() {
604607
return $this->head == null;
605608
}
606609

610+
/**
611+
* @inheritDoc
612+
*/
613+
public function getIterator() {
614+
return new LinkedListIterator($this);
615+
}
616+
607617
/**
608618
* Specify data which should be serialized to JSON
609619
*
@@ -614,24 +624,8 @@ public function isEmpty() {
614624
*/
615625
public function jsonSerialize() {
616626
return [
617-
"head" => $this->head,
627+
"head" => $this->getHead(),
618628
];
619629
}
620630

621-
//TODO implement
622-
//protected function removeDuplicates() {
623-
// $node = $this->head;
624-
// $previous = $this->head;
625-
// $visited = [];
626-
//
627-
// while ($node !== null) {
628-
// if (in_array($node->getValue(), $visited)) {
629-
// $previous->setNext($node->getNext());
630-
// } else {
631-
// $visited[] = $node->getValue();
632-
// $previous = $node;
633-
// }
634-
// $node = $node->getNext();
635-
// }
636-
//}
637631
}
+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
declare(strict_types=1);
3+
/**
4+
* MIT License
5+
*
6+
* Copyright (c) 2018 Dogan Ucar, <[email protected]>
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in all
16+
* copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24+
* SOFTWARE.
25+
*/
26+
27+
namespace doganoo\PHPAlgorithms\Common\Iterator;
28+
29+
use doganoo\PHPAlgorithms\Common\Abstracts\AbstractLinkedList;
30+
use doganoo\PHPAlgorithms\Datastructure\Lists\Node;
31+
use Iterator;
32+
33+
/**
34+
* Class LinkedListIterator
35+
* @package doganoo\PHPAlgorithms\Common\Iterator
36+
*/
37+
class LinkedListIterator implements Iterator {
38+
39+
/** @var AbstractLinkedList $linkedList */
40+
private $linkedList = null;
41+
/** @var Node $root */
42+
private $root = null;
43+
44+
/**
45+
* LinkedListIterator constructor.
46+
* @param AbstractLinkedList $linkedList
47+
*/
48+
public function __construct(AbstractLinkedList $linkedList) {
49+
$this->linkedList = $linkedList;
50+
$this->root = $this->linkedList->getHead();
51+
}
52+
53+
/**
54+
* @inheritDoc
55+
*/
56+
public function current() {
57+
return $this->root;
58+
}
59+
60+
/**
61+
* @inheritDoc
62+
*/
63+
public function next() {
64+
$this->root = $this->root->getNext();
65+
return $this->root;
66+
}
67+
68+
/**
69+
* @inheritDoc
70+
*/
71+
public function key() {
72+
return $this->root->getKey();
73+
}
74+
75+
/**
76+
* @inheritDoc
77+
*/
78+
public function valid() {
79+
return null !== $this->root;
80+
}
81+
82+
/**
83+
* @inheritDoc
84+
*/
85+
public function rewind() {
86+
$this->root = $this->linkedList->getHead();
87+
}
88+
89+
}

src/Datastructure/Lists/LinkedList/DoublyLinkedList.php

+2-10
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public function append(?Node $node): bool {
4242
if ($node === null) {
4343
return false;
4444
}
45+
4546
/*
4647
* need to clone the object otherwise the object
4748
* references are going crazy.
@@ -73,7 +74,7 @@ public function append(?Node $node): bool {
7374
/**
7475
* prepends a node on top of the list
7576
*
76-
* @param \doganoo\PHPAlgorithms\Datastructure\Lists\Node|null $node
77+
* @param Node|null $node
7778
* @return bool
7879
*/
7980
public function prepend(?Node $node): bool {
@@ -102,13 +103,4 @@ public function prepend(?Node $node): bool {
102103
return true;
103104
}
104105

105-
/**
106-
* returns a new instance of DoublyLinkedList
107-
*
108-
* @return AbstractLinkedList
109-
*/
110-
protected function getEmptyInstance(): AbstractLinkedList {
111-
return new DoublyLinkedList();
112-
}
113-
114106
}

src/Datastructure/Lists/LinkedList/SinglyLinkedList.php

+3-10
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030

3131
use doganoo\PHPAlgorithms\Common\Abstracts\AbstractLinkedList;
3232
use doganoo\PHPAlgorithms\Datastructure\Lists\Node;
33+
use Exception;
34+
use Traversable;
3335

3436
/**
3537
* Class SinglyLinkedList
@@ -75,7 +77,7 @@ public function append(?Node $node): bool {
7577
* set to head and the head is set to the new node in order to create
7678
* the new head.
7779
*
78-
* @param \doganoo\PHPAlgorithms\Datastructure\Lists\Node $node
80+
* @param Node $node
7981
* @return bool
8082
*/
8183
public function prepend(?Node $node): bool {
@@ -87,13 +89,4 @@ public function prepend(?Node $node): bool {
8789
return true;
8890
}
8991

90-
/**
91-
* returns a new instance of SinglyLinkedList
92-
*
93-
* @return AbstractLinkedList
94-
*/
95-
protected function getEmptyInstance(): AbstractLinkedList {
96-
return new SinglyLinkedList();
97-
}
98-
9992
}

0 commit comments

Comments
 (0)