1
+ <?php
2
+ /**
3
+ * Created by PhpStorm.
4
+ * User: bert
5
+ * Date: 3/10/18
6
+ * Time: 9:46
7
+ */
8
+
9
+ namespace App \Chapter03 ;
10
+
11
+
12
+ class DoublyLinkedList
13
+ {
14
+ private $ _firstNode = NULL ;
15
+ private $ _lastNode = NULL ;
16
+ private $ _totalNodes = 0 ;
17
+
18
+
19
+ /**
20
+ * Inserts a new node at the first position of the doubly linked list.
21
+ * We must check whether the list is empty (new node is both first and last) or not (mark new node as
22
+ * beeing the first and assign previous first node as new node's next AND previous first node's previous to new node)
23
+ * @param string|NULL $data
24
+ * @return bool
25
+ */
26
+ public function insertAtFirst (string $ data = NULL )
27
+ {
28
+ $ newNode = new DoublyListNode ($ data );
29
+
30
+ if ($ this ->_firstNode === NULL ) {
31
+ $ this ->_firstNode = &$ newNode ;
32
+ $ this ->_lastNode = $ newNode ;
33
+ } else {
34
+ $ currentFirstNode = $ this ->_firstNode ;
35
+ $ this ->_firstNode = &$ newNode ;
36
+ $ newNode ->next = $ currentFirstNode ;
37
+ $ currentFirstNode ->prev = $ newNode ;
38
+ }
39
+ $ this ->_totalNodes ++;
40
+ return true ;
41
+ }
42
+
43
+ /**
44
+ * Inserts a new node at the last position of the doubly linked list.
45
+ * We must check whether the list is empty (new node is both first and last) or not (mark new node as beeing the last
46
+ * and set the previous and next properties accordingly.
47
+ * @param string|NULL $data
48
+ * @return bool
49
+ */
50
+ public function insertAtLast (string $ data = NULL )
51
+ {
52
+ $ newNode = new DoublyListNode ($ data );
53
+
54
+ if ($ this ->_firstNode === NULL ) {
55
+ $ this ->_firstNode = &$ newNode ;
56
+ $ this ->_lastNode = $ newNode ;
57
+ } else {
58
+ $ currentNode = $ this ->_lastNode ;
59
+ $ currentNode ->next = $ newNode ;
60
+ $ newNode ->prev = $ currentNode ;
61
+ $ this ->_lastNode = $ newNode ;
62
+ }
63
+ $ this ->_totalNodes ++;
64
+ return true ;
65
+ }
66
+
67
+ /**
68
+ * Inserts a new node before a specific node.
69
+ * We need to find the node and based on its position, change the next and previous properties of the new node,
70
+ * target node and the node before the target node.
71
+ * @param string|NULL $data
72
+ * @param string|NULL $query
73
+ */
74
+ public function insertBefore (string $ data = NULL , string $ query = NULL )
75
+ {
76
+ $ newNode = new DoublyListNode ($ data );
77
+ if ($ this ->_firstNode ) {
78
+ $ previous = NULL ;
79
+ $ currentNode = $ this ->_firstNode ;
80
+ while ($ currentNode !== NULL ) {
81
+ if ($ currentNode ->data === $ query ) {
82
+ $ newNode ->next = $ currentNode ;
83
+ $ currentNode ->prev = $ newNode ;
84
+ $ previous ->next = $ newNode ;
85
+ $ newNode ->prev = $ previous ;
86
+ $ this ->_totalNodes ++;
87
+ break ;
88
+ }
89
+ $ previous = $ currentNode ;
90
+ $ currentNode = $ currentNode ->next ;
91
+ }
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Inserts a new node after a specific node.
97
+ * We need to find the node and based on its position, change the next and prev properties of the new node, target
98
+ * node and the node after the target node.
99
+ * @param string|NULL $data
100
+ * @param string|NULL $query
101
+ */
102
+ public function insertAfter (string $ data = NULL , string $ query = NULL )
103
+ {
104
+ $ newNode = new DoublyListNode ($ data );
105
+ if ($ this ->_firstNode ) {
106
+ $ nextNode = NULL ;
107
+ $ currentNode = $ this ->_firstNode ;
108
+ while ($ currentNode !== NULL ) {
109
+ if ($ currentNode ->data === $ query ) {
110
+
111
+ // Check if there is a node AFTER the found node
112
+ if ($ nextNode !== NULL ) {
113
+ $ newNode ->next = $ nextNode ;
114
+ }
115
+ // check if the found node is the last node.
116
+ if ($ currentNode === $ this ->_lastNode ) {
117
+ $ this ->_lastNode = $ newNode ;
118
+ }
119
+
120
+ $ currentNode ->next = $ newNode ;
121
+ $ nextNode ->prev = $ newNode ;
122
+ $ newNode ->prev = $ currentNode ;
123
+
124
+ $ this ->_totalNodes ++;
125
+ break ;
126
+ }
127
+ $ currentNode = $ currentNode ->next ;
128
+ $ nextNode = $ currentNode ;
129
+ }
130
+ }
131
+ }
132
+
133
+ /**
134
+ * Deletes the first node of the list.
135
+ * We need to make the second node the first node after removing the item.
136
+ * @return bool
137
+ */
138
+ public function deleteFirst ()
139
+ {
140
+ if ($ this ->_firstNode !== NULL ) {
141
+ // Check if this is the only item in the list and act accordingly.
142
+ if ($ this ->_firstNode ->next !== NULL ) {
143
+ $ this ->_firstNode = $ this ->_firstNode ->next ;
144
+ $ this ->_firstNode ->prev = NULL ;
145
+ } else {
146
+ $ this ->_firstNode = NULL ;
147
+ }
148
+ $ this ->_totalNodes --;
149
+ return true ;
150
+ }
151
+ return false ;
152
+ }
153
+
154
+ /**
155
+ * Deletes the last node of the list.
156
+ * We need to make the second to last node the last node after removing the item.
157
+ * @return bool
158
+ */
159
+ public function deleteLast ()
160
+ {
161
+ if ($ this ->_lastNode !== NULL ) {
162
+ $ currentNode = $ this ->_lastNode ;
163
+ // Check if this is the only item, delete first and last if so.
164
+ if ($ currentNode ->prev === NULL ) {
165
+ $ this ->_firstNode = NULL ;
166
+ $ this ->_lastNode = NULL ;
167
+ } else {
168
+ $ previousNode = $ currentNode ->prev ;
169
+ $ this ->_lastNode = $ previousNode ;
170
+ $ previousNode ->next = NULL ;
171
+ $ this ->_totalNodes --;
172
+ return true ;
173
+ }
174
+ }
175
+ return false ;
176
+ }
177
+
178
+ /**
179
+ * Deletes a given node from the list.
180
+ * We need to make sure that always the previous and next nodes of the found node are tracked, and the next and prev
181
+ * properties of both are set.
182
+ * @param string|NULL $query
183
+ */
184
+ public function delete (string $ query = NULL )
185
+ {
186
+ if ($ this ->_firstNode ) {
187
+ $ previous = NULL ;
188
+ $ currentNode = $ this ->_firstNode ;
189
+ while ($ currentNode !== NULL ) {
190
+ if ($ currentNode ->data === $ query ) {
191
+ // Check if the found node is tha last one in the list.
192
+ if ($ currentNode ->next === NULL ) {
193
+ $ previous ->next = NULL ;
194
+ } else {
195
+ $ previous ->next = $ currentNode ->next ;
196
+ $ currentNode ->next ->prev = $ previous ;
197
+ }
198
+
199
+ $ this ->_totalNodes --;
200
+ break ;
201
+ }
202
+ $ previous = $ currentNode ;
203
+ $ currentNode = $ currentNode ->next ;
204
+ }
205
+ }
206
+ }
207
+
208
+ /**
209
+ * Displays the items in the list moving forward.
210
+ * Starts from the first item.
211
+ */
212
+ public function displayForward ()
213
+ {
214
+ echo "Total book titles: " . $ this ->_totalNodes . PHP_EOL ;
215
+ $ currentNode = $ this ->_firstNode ;
216
+ while ($ currentNode !== NULL ){
217
+ echo $ currentNode ->data . PHP_EOL ;
218
+ $ currentNode = $ currentNode ->next ;
219
+ }
220
+ }
221
+
222
+ /**
223
+ * Displays the items in the list moving backward.
224
+ * Starts from the last item.
225
+ */
226
+ public function displayBackward ()
227
+ {
228
+ echo "Total book titles: " . $ this ->_totalNodes . PHP_EOL ;
229
+ $ currentNode = $ this ->_lastNode ;
230
+ while ($ currentNode !== NULL ){
231
+ echo $ currentNode ->data . PHP_EOL ;
232
+ $ currentNode = $ currentNode ->prev ;
233
+ }
234
+ }
235
+ }
0 commit comments