Skip to content

Commit e8e68f4

Browse files
committed
Implemented DoublyLinkedList data structure
1 parent 8e6dadc commit e8e68f4

File tree

2 files changed

+236
-0
lines changed

2 files changed

+236
-0
lines changed
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
//: [Previous](@previous)
2+
3+
import Foundation
4+
5+
private class DoublyNode<T>: CustomStringConvertible, CustomDebugStringConvertible {
6+
7+
// MARK: - Conformances to CustomStringConvertible & CustomDebugStringConvertible protocols
8+
9+
var description: String {
10+
return representation()
11+
}
12+
13+
var debugDescription: String {
14+
return representation()
15+
}
16+
17+
private func representation() -> String {
18+
return "\(String(describing: data))"
19+
}
20+
21+
// MARK: - Properties
22+
23+
fileprivate var next: DoublyNode<T>?
24+
fileprivate var data: T
25+
fileprivate var previous: DoublyNode<T>?
26+
27+
// MARK: - Initailziers
28+
29+
init(data: T, next: DoublyNode<T>?, previous: DoublyNode<T>?) {
30+
self.data = data
31+
self.next = next
32+
self.previous = previous
33+
}
34+
}
35+
36+
public struct DoublyLinkedList<T> {
37+
38+
// MARK: - Fileprivate properties
39+
40+
fileprivate var head: DoublyNode<T>?
41+
fileprivate var tail: DoublyNode<T>?
42+
fileprivate var current: DoublyNode<T>?
43+
44+
fileprivate var _count: Int = 0
45+
46+
// MARK: - Public properties
47+
48+
public var count: Int {
49+
return _count
50+
}
51+
52+
public var front: T? {
53+
return head?.data
54+
}
55+
56+
public var back: T? {
57+
return tail?.data
58+
}
59+
60+
public var isEmpty: Bool {
61+
return count == 0
62+
}
63+
64+
// MARK: - Initailizers
65+
66+
public init() {
67+
head = nil
68+
tail = nil
69+
current = nil
70+
}
71+
72+
public init<S: Sequence>(sequence: S) where S.Iterator.Element == T {
73+
for element in sequence {
74+
push(newTail: element)
75+
}
76+
}
77+
78+
// MARK: - Methods
79+
80+
public mutating func next() -> T? {
81+
current = current?.next
82+
return current?.data
83+
}
84+
85+
public mutating func previous() -> T? {
86+
current = current?.previous
87+
return current?.data
88+
}
89+
90+
public mutating func push(newHead element: T) {
91+
var node: DoublyNode<T>
92+
93+
if count == 0 {
94+
node = DoublyNode<T>(data: element, next: nil, previous: nil)
95+
tail = node
96+
} else {
97+
node = DoublyNode<T>(data: element, next: head, previous: nil)
98+
head?.previous = node
99+
}
100+
101+
head = node
102+
_count += 1
103+
104+
if count == 1 {
105+
current = head
106+
} else if head === current {
107+
current = head?.next
108+
}
109+
}
110+
111+
public mutating func push(newTail element: T) {
112+
var node: DoublyNode<T>
113+
114+
if count == 0 {
115+
node = DoublyNode<T>(data: element, next: nil, previous: nil)
116+
head = node
117+
} else {
118+
node = DoublyNode<T>(data: element, next: nil, previous: tail)
119+
tail?.next = node
120+
}
121+
122+
tail = node
123+
_count += 1
124+
125+
if count == 1 {
126+
current = tail
127+
} else if tail === current {
128+
current = tail?.previous
129+
}
130+
}
131+
132+
@discardableResult
133+
public mutating func removeHead() -> T? {
134+
if isEmpty { return nil }
135+
136+
let element = head?.data
137+
head = head?.next
138+
_count -= 1
139+
140+
return element
141+
}
142+
143+
public mutating func removeTail() -> T? {
144+
if isEmpty { return nil }
145+
146+
let element = tail?.data
147+
tail = tail?.previous
148+
_count -= 1
149+
return element
150+
}
151+
152+
// MARK: - Private methods
153+
154+
private mutating func reset() {
155+
head = nil
156+
tail = nil
157+
current = nil
158+
}
159+
}
160+
161+
extension DoublyLinkedList: CustomStringConvertible, CustomDebugStringConvertible {
162+
163+
// MARK: - Conformances to CustomStringConvertible & CustomDebugStringConvertible protocols
164+
165+
public var description:String {
166+
return representation()
167+
}
168+
169+
public var debugDescription:String {
170+
return representation()
171+
}
172+
173+
// MARK: - Private methods
174+
175+
private func representation() -> String {
176+
var output = "("
177+
var c = 0
178+
var x = head
179+
180+
while nil !== x {
181+
output += "\(String(describing: x))"
182+
c += 1
183+
if c != count {
184+
output += ", "
185+
}
186+
x = x!.next
187+
}
188+
output += ")"
189+
return output
190+
}
191+
}
192+
193+
extension DoublyLinkedList: ExpressibleByArrayLiteral {
194+
195+
public init(arrayLiteral elements: T...) {
196+
for element in elements {
197+
push(newTail: element)
198+
}
199+
}
200+
}
201+
202+
extension DoublyLinkedList: Sequence {
203+
204+
public func makeIterator() -> AnyIterator<T> {
205+
var iterator = head
206+
207+
return AnyIterator {
208+
defer { iterator = iterator?.next }
209+
return iterator?.data
210+
}
211+
}
212+
213+
}
214+
215+
//: Usage:
216+
217+
var list: DoublyLinkedList = [1,2,4,5,6,7]
218+
print(list)
219+
220+
list.head
221+
list.tail
222+
223+
list.removeHead()
224+
print(list)
225+
226+
list.removeTail()
227+
print(list)
228+
229+
list.push(newHead: 99)
230+
print(list)
231+
232+
list.push(newTail: 101)
233+
print(list)
234+
235+
//: [Next](@next)

Data Structures.playground/contents.xcplayground

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@
1414
<page name='BinarySearchTree'/>
1515
<page name='Red-Black Tree'/>
1616
<page name='Dequeue'/>
17+
<page name='DoublyLinkedList'/>
1718
</pages>
1819
</playground>

0 commit comments

Comments
 (0)