tl;dr
Wrote a linked list queue in Swift
After writing a stack in Swift, I decided that I try writing a queue in Swift.
Again, this tutorial requires you to have XCode 6 Beta in order to run Swift.
1. Define classes
{% highlight swift %} import Foundation
class Queue {
} {% endhighlight %}
{% highlight swift %} import Foundation
class Node {
} {% endhighlight %}
I created two classes in different files in XCode.
2. Attributes and Constructors for Node class
{% highlight swift %}
class Node<T:NSObject> {
var value: T? = nil
var next: Node
init() {
}
init(value: T) {
self.value = value
}
} {% endhighlight %}
Node
has two attributes: value
and next
.
value
has an optional generic type T
which may have nil
value.
next
has an optional Nodenil
value.
Node
has two init
constructors: one that takes value
as an
argument, and another one that doesn't take any argument.
3. Attributes and Constructor for Queue class
{% highlight swift %} import Foundation
class Queue<T:NSObject> {
var count: Int = 0
var head: Node
init() {
}
} {% endhighlight %}
Queue
class has three attributes count
, head
and tail
.
head
is the beginning of the queue and tail
is the end of the queue.
4. isEmpty
function
{% highlight swift %} import Foundation
class Queue<T:NSObject> {
var count: Int = 0
var head: Node
init() {
}
func isEmpty() -> Bool {
return self.count == 0
}
} {% endhighlight %}
isEmpty
is simply comparing self.count == 0
.
If the queue is empty, returns true, if not, false.
5. enqueue
function
{% highlight swift %} import Foundation
class Queue<T:NSObject> {
var count: Int = 0
var head: Node
init() {
}
func isEmpty() -> Bool {
return self.count == 0
}
func enqueue(value: T) {
var node = Node<T>(value: value)
if self.isEmpty() {
self.head = node
self.tail = node
} else {
node.next = self.head
self.head = node
}
self.count++
}
} {% endhighlight %}
enqueue
function takes a value and creates a node out of it.
It first checks if the queue is empty.
If it is empty, queue's head and tail are set to the node.
If not, the node is inserted in front of the current head of the queue.
Then increment count
.
6. dequeue
function
{% highlight swift %} import Foundation
class Queue<T:NSObject> {
var count: Int = 0
var head: Node
init() {
}
func isEmpty() -> Bool {
return self.count == 0
}
func enqueue(value: T) {
var node = Node<T>(value: value)
if self.isEmpty() {
self.head = node
self.tail = node
} else {
node.next = self.head
self.head = node
}
self.count++
}
func dequeue() -> T? {
if self.isEmpty() {
return nil
} else if self.count == 1 {
var temp: Node<T> = self.tail
self.count--
return temp.value
} else {
var temp: Node<T> = self.tail
// ??????
self.count--
return temp.value
}
}
} {% endhighlight %}
dequeue
function has 3 cases to handle.
- When the queue is empty
- When the queue has one node
- When the queue has more than one node
In case 1, you just return nil
.
In case 2, you return the queue's tail node and decrement.
In case 3, you want to return the queue's tail node as well.
But the problem is that we need to know the reference to the node right before
the tail node. We need prev
attribute for nodes.
7. Adding prev
attribute to Node class
{% highlight swift %} import Foundation
class Node<T:NSObject> {
var value: T? = nil
var next: Node
init() {
}
init(value: T) {
self.value = value
}
} {% endhighlight %}
prev
attribute is written the same way as next
.
{% highlight swift %} import Foundation
class Queue<T:NSObject> {
var count: Int = 0
var head: Node
init() {
}
func isEmpty() -> Bool {
return self.count == 0
}
func enqueue(value: T) {
var node = Node<T>(value: value)
if self.isEmpty() {
self.head = node
self.tail = node
} else {
node.next = self.head
self.head.prev = node
self.head = node
}
self.count++
}
func dequeue() -> T? {
if self.isEmpty() {
return nil
} else if self.count == 1 {
var temp: Node<T> = self.tail
self.count--
return temp.value
} else {
var temp: Node<T> = self.tail
self.tail = self.tail.prev!
self.count--
return temp.value
}
}
} {% endhighlight %}
We add self.tail = self.tail.prev!
, which
sets the new tail node, when the current tail
node is removed.
You can see the full source code on github.