-
Notifications
You must be signed in to change notification settings - Fork 65
/
DoublyLinkedList.java
330 lines (305 loc) · 7.98 KB
/
DoublyLinkedList.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
/**
* Data-Structures-In-Java
* DoublyLinkedList.java
*/
package com.deepak.data.structures.LinkedList;
/**
* Implementation of Doubly linked list
*
* <br> Operations supported are :
* - Inserting a element in the list - This can be at beginning, at end or at a given position.
* - Traversing through linked list. - This can happen in any direction with doubly linked list
* - Check the size of the list.
* - Check if list is empty.
* - Search an element by index.
* - Search an element by value.
* - Delete an element from the list - This can again be at beginning, at end or at given position.
* - Converting a Array from linked list.
* </br>
*
* @author Deepak
*
* @param <E>
*/
public class DoublyLinkedList<E> {
/* Head is needed to keep track of first node */
private Node<E> head;
/* Tail is needed to keep track of last node */
private Node<E> tail;
/* Size to keep track of number of elements in list.
* This should be increased by 1 when a element is added
* and should be reduced by 1 when a element is deleted */
private int size = 0;
/**
* Inserts a element into a linked list at head position.
* This does not require traversal through entire list.
*
* <br> Complexity :
* Since there is no traversal involved here, and insertion
* always happens at the head, this can be done in constant
* time. Hence, complexity comes out to be O(1)
* </br>
*
* @param value
*/
public void insertAtHead(E value) {
Node<E> newNode = new Node<E>(value);
if (null == head) {
/* If list is empty */
newNode.next = null;
newNode.prev = null;
head = newNode;
tail = newNode;
size++;
} else {
newNode.next = head;
newNode.prev = null;
head.prev = newNode;
head = newNode;
size++;
}
}
/**
* Inserts a element into a linked list at tail position.
* This does not needs traversal through entire list before insertion happens.
*
* <br> Complexity :
* Since, traversal through entire list is NOT involved here before
* new node gets inserted, and let's assume list has n elements,
* so insertion at tail will take O(1) time
* </br>
*
* @param value
*/
public void insertAtTail(E value) {
Node<E> newNode = new Node<E>(value);
if (null == tail) {
/* If list is empty */
newNode.next = null;
newNode.prev = null;
head = newNode;
tail = newNode;
size++;
} else {
tail.next = newNode;
newNode.next = null;
newNode.prev = tail;
tail = newNode;
size++;
}
}
/**
* Inserts a element into a linked list at a given position.
* This needs traversal through the linked list till the given position.
*
* <br> Complexity :
* This insertion can possibly happen at last node, means we will have complexity
* as O(1) as explained above.
* we may have to traverse entire linked list. On an average case with
* linked list having n elements, this will take n/2 time and after ignoring
* the constant term, complexity comes out to be O(n)
* </br>
*
* @param value
* @param position
*/
public void insertAtPosition(E value, int position) {
if (position < 0 || position > size) {
throw new IllegalArgumentException("Position is Invalid");
}
/* Conditions check passed, let's insert the node */
if (position == 0) {
/* Insertion should happen at head */
insertAtHead(value);
} else if (position == size -1) {
/* Insertion should happen at tail */
insertAtTail(value);
} else {
/* Insertion is happening somewhere in middle */
Node<E> currentNode = head;
for (int i = 0; i < position; i++) {
currentNode = currentNode.next;
}
Node<E> previousNode = currentNode.prev;
/* Insertion of new node will happen in
* between previous node and current node */
Node<E> newNode = new Node<E>(value);
newNode.next = currentNode;
newNode.prev = previousNode;
previousNode.next = newNode;
currentNode.prev = newNode;
size++;
}
}
/**
* Traverse the linked list in forward direction and print the items
*/
public void traverseForward() {
Node<E> temp = head;
while (temp != null) {
System.out.println(temp.item);
temp = temp.next;
}
}
/**
* Traverse the linked list in backward direction and print the items
*/
public void traverseBackward() {
Node<E> temp = tail;
while (temp != null) {
System.out.println(temp.item);
temp = temp.prev;
}
}
/**
* Returns the size of the linked list
*
* @return {@link int}
*/
public int size() {
return size;
}
/**
* Returns true, if linked list is empty
*
* @return {@link boolean}
*/
public boolean isEmpty() {
return size == 0;
}
/**
* Returns the Node containing data item after searching
* for a given index. If invalid index is passed, proper
* exception is thrown.
*
* @param index
* @return {@link Node<E>}
*/
public Node<E> searchByIndex(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("Invalid index passed while searching for a value");
}
/* Validation passed, let's search for value using the index */
Node<E> temp = head;
for (int i = 0; i < index; i++) {
/* Start from 0 and go till one less then index
* because we are jumping to next node inside the loop */
temp = temp.next;
}
return temp;
}
/**
* Returns the node containing data item after searching
* for a given value. If there are multiple same values
* in linked list, first one will be returned.
*
* @param value
* @return {@link Node<E>}
*/
public Node<E> searchByValue(E value) {
/* Traverse through each node until this value is found */
Node<E> temp = head;
while (null != temp.next && temp.item != value) {
temp = temp.next;
}
if (temp.item == value) {
return temp;
}
return null;
}
/**
* Delete's the element present at head node
*/
public void deleteFromHead() {
/* If list is empty, return */
if (null == head) {
return;
}
Node<E> temp = head;
head = temp.next;
head.prev = null;
size--;
}
/**
* Delete's the element present at tail node
*/
public void deleteFromTail() {
/* If list is empty, return */
if (null == tail) {
return;
}
Node<E> temp = tail;
tail = temp.prev;
tail.next = null;
size--;
}
/**
* Delete's the element present at given position
*
* @param position
*/
public void deleteFromPosition(int position) {
if (position < 0 || position >= size) {
throw new IllegalArgumentException("Position is Invalid");
}
/* Conditions check passed, let's delete the node */
Node<E> nodeToBeDeleted = head;
for (int i = 0; i < position; i++) {
nodeToBeDeleted = nodeToBeDeleted.next;
}
Node<E> previousNode = nodeToBeDeleted.prev;
Node<E> nextNode = nodeToBeDeleted.next;
previousNode.next = nextNode;
nextNode.prev = previousNode;
size--;
}
/**
* Returns a array containing each element
* from the list from start to end
*
* @return
*/
public Object[] toArray() {
Object[] result = new Object[size];
int i = 0;
for (Node<E> x = head; x != null; x = x.next) {
result[i++] = x.item;
}
return result;
}
/**
* Node class of a linked list
* This is needed since entire linked list is a collection
* of nodes connected to each other through links
*
* <br> We are keeping it generic so that it can be used with
* Integer, String or something else </br>
*
* <br> Each node contains a data item, a pointer to next node
* and pointer to previous node.
* Since this is a Doubly linked list and each node points in
* both directions i.e forward and backward.
* We maintain two pointers, one to next node and one to previous node </br>
*
* @author Deepak
*
* @param <T>
*/
public class Node<T> {
/* Data item in the node */
T item;
/* Pointer to next node */
Node<T> next;
/* Pointer to previous node */
Node<T> prev;
/* Constructor to create a node */
public Node(T item) {
this.item = item;
}
/* toString implementation to print just the data */
@Override
public String toString() {
return String.valueOf(item);
}
}
}