Skip to content

Commit 638a15f

Browse files
refactored DoubleLinkedList
1 parent fd56ccc commit 638a15f

File tree

4 files changed

+395
-217
lines changed

4 files changed

+395
-217
lines changed

src/main/kotlin/structures/DoubleLinkedList.kt

+176-138
Original file line numberDiff line numberDiff line change
@@ -2,94 +2,135 @@ package structures
22

33
/**
44
*
5-
* data structure: doubly linked list
5+
* LinkedList a data structure consisting of a collection of nodes that contain a link to the next/previous node.
66
*
7-
* description: in a doubly linked list, each element stores a link to the previous and next elements
8-
*
9-
* time to insert an element at the beginning and end of the list: O(1)
10-
* insertion time in the middle by index: O(n)
11-
* delete: O(n)
7+
* In the double LinkedList each node contains a link to the previous and next elements
128
*
139
*/
1410

15-
class DoubleLinkedList<T>(
16-
/**
17-
* stores a reference to the first element of the list
18-
*
19-
* if the list is empty, then the reference is null
20-
*/
21-
private var first: Node<T>? = null,
22-
/**
23-
* stores a reference to the last element of the list
24-
*
25-
* if the list is empty, then the reference is null
26-
*/
27-
private var last: Node<T>? = null
28-
) {
11+
class DoubleLinkedList<T> {
2912

30-
/**
31-
* stores the number of elements in the list
32-
*
33-
*/
34-
private var count: Int = 0
13+
private var head: Node<T>? = null
14+
private var tail: Node<T>? = null
3515

36-
/**
37-
* doubly linked list node
38-
*
39-
* @property value - node value
40-
* @property prev - link to the previous element (assuming the element is not the first one)
41-
* @property next - link to the next element (assuming the element is not the last one)
42-
*/
43-
class Node<T>(
44-
private val value: T,
45-
private var prev: Node<T>? = null,
46-
private var next: Node<T>? = null
47-
) {
16+
private var size: Int = 0
17+
18+
val isEmpty: Boolean
19+
get() = head == null
4820

49-
fun changeNext(next: Node<T>? = null) {
50-
this.next = next
21+
// Complexity: O(n)
22+
val list: List<T>
23+
get() {
24+
val nodes = mutableListOf<T>()
25+
var node = head
26+
while (node != null) {
27+
val nodeValue = node.value()
28+
if (nodeValue != null) {
29+
nodes.add(nodeValue)
30+
}
31+
node = node.next()
32+
}
33+
return nodes
5134
}
5235

53-
fun changePrev(prev: Node<T>? = null) {
54-
this.prev = prev
36+
// Complexity: O(n)
37+
val reversedList: List<T>
38+
get() {
39+
val nodes = mutableListOf<T>()
40+
var node = tail
41+
while (node != null) {
42+
val nodeValue = node.value()
43+
if (nodeValue != null) {
44+
nodes.add(nodeValue)
45+
}
46+
node = node.previous()
47+
}
48+
return nodes
5549
}
5650

57-
fun next() = next
58-
fun prev() = prev
59-
fun value() = value
51+
/**
52+
* Complexity:
53+
* worst time: O(n)
54+
* best time: O(1)
55+
* average time: O(n)
56+
*/
57+
fun add(index: Int, value: T) : Boolean {
58+
if (head == null) return false
6059

61-
fun isOne() = prev == null && next == null
62-
fun isFirst() = prev == null
63-
fun isLast() = next == null
60+
var i = 0
61+
var node = head
62+
var prevNode = head
63+
while (prevNode != null && node != null) {
64+
if (i == index) {
65+
val newNode = Node(value)
66+
newNode.changeNext(node)
67+
newNode.changePrevious(prevNode)
68+
prevNode.changeNext(newNode)
69+
size++
70+
return true
71+
}
72+
i++
73+
prevNode = node
74+
node = node.next()
75+
}
76+
77+
return false
6478
}
6579

80+
fun add(value: T) = addLast(value)
81+
6682
/**
67-
* returns the number of elements in the list
83+
* Complexity:
84+
* worst time: O(1)
85+
* best time: O(1)
86+
* average time: O(1)
6887
*/
69-
fun size() = count
88+
fun addFirst(value: T) {
89+
val headNode = head
90+
head = if (headNode == null) {
91+
Node(value)
92+
} else {
93+
val newNode = Node(value = value, next = headNode)
94+
headNode.changePrevious(newNode)
95+
newNode
96+
}
97+
if (tail == null) {
98+
tail = head
99+
}
100+
size++
101+
}
70102

71103
/**
72-
* converts a list into a normal Kotlin list for visual representation, returns Kotlin a list of elements
104+
* Complexity:
105+
* worst time: O(1)
106+
* best time: O(1)
107+
* average time: O(1)
73108
*/
74-
fun toList() : List<T> {
75-
if (first == null) return listOf()
76-
77-
val list = mutableListOf<T>()
78-
var node = first
79-
while (node != null) {
80-
list.add(node.value())
81-
node = node.next()
109+
fun addLast(value: T) {
110+
val tailNode = tail
111+
tail = if (tailNode == null) {
112+
Node(value)
113+
} else {
114+
val newNode = Node(value = value, previous = tailNode)
115+
tailNode.changeNext(newNode)
116+
newNode
117+
}
118+
if (head == null) {
119+
head = tail
82120
}
83-
return list
121+
size++
84122
}
85123

86124
/**
87-
* checks if an element [value] is in the list, returns true if the value exists in the list
125+
* Complexity:
126+
* worst time: O(n)
127+
* best time: O(1)
128+
* average time: O(n)
88129
*/
89130
fun contains(value: T) : Boolean {
90-
if (first == null) return false
131+
if (head == null) return false
91132

92-
var node = first
133+
var node = head
93134
while (node != null) {
94135
if (node.value() == value) {
95136
return true
@@ -100,113 +141,110 @@ class DoubleLinkedList<T>(
100141
}
101142

102143
/**
103-
* checks if the list is empty, returns true if the list is empty
104-
*/
105-
fun isEmpty() = first == null
106-
107-
/**
108-
* removes an element [value] from the list, returns true if the element was successfully removed
144+
* Complexity:
145+
* worst time: O(n)
146+
* best time: O(1)
147+
* average time: O(n)
109148
*/
110149
fun remove(value: T) : Boolean {
111-
if (first == null) return false
150+
if (head == null) return false
112151

113-
var node = first
152+
var previous: Node<T>? = null
153+
var node = head
114154

115155
while (node != null) {
116156
if (node.value() == value) {
117-
if (node.isOne()) {
118-
first = null
119-
last = null
120-
} else if (node.isFirst()) {
121-
val next = node.next()
122-
next?.changePrev(null)
123-
first = next
124-
} else if (node.isLast()) {
125-
val prev = node.prev()
126-
prev?.changeNext(null)
127-
last = prev
128-
} else {
129-
node.prev()?.changeNext(node.next())
130-
node.next()?.changePrev(node.prev())
157+
val nextNode = node.next()
158+
previous?.changeNext(nextNode)
159+
nextNode?.changePrevious(previous)
160+
161+
if (node === head) {
162+
head = nextNode
131163
}
132-
count--
164+
165+
if (node === tail) {
166+
tail = previous
167+
}
168+
169+
node.changePrevious(null)
170+
node.changeNext(null)
171+
node.changeValue(null)
172+
173+
size--
133174
return true
134175
}
176+
previous = node
135177
node = node.next()
136178
}
179+
137180
return false
138181
}
139182

140-
/**
141-
* adds element [value] by index [index], returns true if the element was successfully added at the specified index
142-
*/
143-
fun add(index: Int, value: T) : Boolean {
183+
// Complexity: O(n)
184+
fun clear() {
185+
var node = head
186+
while (node != null) {
187+
val currentNode = node
188+
189+
node = node.next()
144190

145-
if (first == null) return false
191+
currentNode.changeNext(null)
192+
currentNode.changePrevious(null)
193+
currentNode.changeValue(null)
194+
}
146195

147-
var i = 0
148-
var node = first
196+
head = null
197+
tail = null
198+
size = 0
199+
}
200+
201+
override fun toString(): String {
202+
val builder = StringBuilder()
203+
builder.append("size: $size\n")
204+
builder.append("elements: ")
205+
206+
var node = head
149207
while (node != null) {
150-
if (i == index) {
151-
val newNode = Node(value)
152208

153-
newNode.changePrev(node.prev())
154-
newNode.changeNext(node)
209+
// it's necessary to see the correct node connections
210+
if (node.previous() != null) {
211+
builder.append("- ")
212+
}
155213

156-
node.prev()?.changeNext(newNode)
157-
node.changePrev(newNode)
214+
builder.append(node.value())
158215

159-
count++
160-
return true
216+
// it's necessary to see the correct node connections
217+
if (node.next() != null) {
218+
builder.append(" -")
161219
}
162-
i++
220+
163221
node = node.next()
164222
}
165223

166-
return false
224+
return builder.toString()
167225
}
168226

169-
/**
170-
* similar addLast [addLast] method
171-
*/
172-
fun add(value: T) = addLast(value)
227+
class Node<T>(
228+
private var value: T? = null,
229+
private var previous: Node<T>? = null,
230+
private var next: Node<T>? = null
231+
) {
173232

174-
/**
175-
* adds an element [value] to the beginning of the list
176-
*/
177-
fun addFirst(value: T) {
178-
val firstNode = first
179-
first = if (firstNode == null) {
180-
Node(value)
181-
} else {
182-
val newNode = Node(value)
183-
newNode.changeNext(firstNode)
184-
firstNode.changePrev(newNode)
185-
newNode
186-
}
187-
if (last == null) {
188-
last = first
233+
fun next() = next
234+
fun changeNext(node: Node<T>? = null) {
235+
next = node
189236
}
190-
count++
191-
}
192237

193-
/**
194-
* adds an element [value] to the end of the list
195-
*/
196-
fun addLast(value: T) {
197-
val lastNode = last
198-
last = if (lastNode == null) {
199-
Node(value)
200-
} else {
201-
val newNode = Node(value)
202-
lastNode.changeNext(newNode)
203-
newNode.changePrev(lastNode)
204-
newNode
238+
fun previous() = previous
239+
fun changePrevious(node: Node<T>? = null) {
240+
previous = node
205241
}
206-
if (first == null) {
207-
first = last
242+
243+
fun value() = value
244+
fun changeValue(newValue: T?) {
245+
value = newValue
208246
}
209-
count++
247+
210248
}
211249

212250
}

0 commit comments

Comments
 (0)