-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathContents.swift
161 lines (114 loc) · 3.58 KB
/
Contents.swift
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
//: [Previous](@previous)
public struct LinkedList<T> {
// MARK: - Private properties
fileprivate var head: Node<T>?
fileprivate var _count: Int = 0
// MARK: - Public properties
public var count: Int {
return _count
}
// MARK: - Initializers
public init() {
head = nil
}
public init<S: Sequence>(sequence: S) where S.Iterator.Element == T {
for element in sequence {
push(element: element)
}
}
// MARK: - API Methods
public mutating func push(element: T) {
let node = Node<T>(data: element)
node.next = head
head = node
_count += 1
}
public mutating func pop() -> T? {
if isEmpty() { return nil }
let element = head?.data
head = head?.next
_count -= 1
return element
}
public func peek() -> T? {
return head?.data
}
public func isEmpty() -> Bool {
return _count == 0
}
}
/// Node class represents a generic node element that is used to construct resursuve linked list
private class Node<T> {
fileprivate var next: Node<T>?
fileprivate var data: T
init(data: T) {
next = nil
self.data = data
}
}
// MARK: - Conformance to CusomStringConvertable and CustomDebugStringConvertable protocols
extension LinkedList: CustomStringConvertible, CustomDebugStringConvertible {
// MARK: - Conformance to the protocols
public var description: String {
return composeDescription()
}
public var debugDescription: String {
return composeDescription()
}
// MARK: - Utliity mehtods
private func composeDescription() -> String {
var description = "["
var lastNode = head
while lastNode != nil {
description += "\(String(describing: lastNode?.data))"
lastNode = lastNode?.next
if lastNode != nil {
description += ","
}
}
description += "]"
return description
}
}
// MARK: - Conformance to ExpressibleByArrayLiteral protocol that allows to treat the LinkedList as an array when initializing it
extension LinkedList: ExpressibleByArrayLiteral {
public init(arrayLiteral elements: T...) {
for element in elements {
push(element: element)
}
}
}
/// Custom generic struct that conforms to IteratorProtocol. The structure receives an instnace of head during initialization pohase that allows us to iterate through the elements in the linked ilst.
public struct LinkedListIterator<T>: IteratorProtocol {
// MARK: - Properties
public typealias Element = T
private var head: Node<Element>?
// MARK: - Initializers
fileprivate init(head: Node<T>?) {
self.head = head
}
// MARK: - Conformacne to the protocol
public mutating func next() -> T? {
guard let uHead = head else { return nil }
let item = uHead.data
head = uHead.next
return item
}
}
// MARK: - Conformance to
extension LinkedList: Sequence {
public typealias Iterator = LinkedListIterator<T>
public func makeIterator() -> LinkedListIterator<T> {
return LinkedListIterator<T>(head: head)
}
}
// MARK: - Usage
var list: LinkedList = [1,2,4,5]
debugPrint(list)
list.pop()
debugPrint(list)
var newList = LinkedList<Int>(sequence: list)
debugPrint(newList)
newList.pop()
debugPrint(newList)
//: [Next](@next)