Swift Algorithm Club: Swift Queue Data Structure
Learn how to implement a Swift queue, including enqueue, dequeue, and peek, in this step by step tutorial. Includes a downloadable Swift playground! By Chris Pilcher.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Swift Algorithm Club: Swift Queue Data Structure
10 mins
The Swift Algorithm Club is an open source project on implementing data structures and algorithms in Swift.
Every month, Kelvin Lau and I feature a cool data structure or algorithm from the club in a tutorial on this site. If you want to learn more about algorithms and data structures, follow along with us!
In this tutorial, you’ll learn how to implement a queue in Swift 3. A queue is one of the most popular data structures, and is fairly simple to implement in Swift.
The queue implementation was first implemented by Matthijs Hollemans, the founder of the Swift Algorithm Club.
Getting Started
A queue is a list where you can only insert new items at the back and remove items from the front. This ensures that the first item you enqueue is also the first item you dequeue. First come, first serve!
Why would you need this? Well, in many algorithms you want to add items to a temporary list at some point and then pull them off this list again at a later time. Often the order in which you add and remove these items matters.
A queue gives you a FIFO or first-in, first-out order. The element you inserted first is also the first one to come out again. It’s only fair! (A very similar data structure, the stack, is LIFO or last-in first-out.)
An example
The easiest way to understand a queue is to see how it’s used.
Imagine you have a queue. Here’s how you would enqueue a number:
queue.enqueue(10)
The queue would now be [ 10 ]. Then you could add the next number to the queue:
queue.enqueue(3)
The queue would now be [ 10, 3 ]. You could add one more number:
queue.enqueue(57)
The queue would now be[ 10, 3, 57 ]. You could dequeue to pull the first element off the front of the queue:
queue.dequeue()
This would return 10 because that was the first number you inserted. The queue would now be [ 3, 57 ]. Every item moved up by one place.
queue.dequeue()
This would returns 3. The next dequeue would return 57, and so on. If the queue is empty, dequeuing would return nil.
Queue Implementation
In this section, you’ll implement a simple general-purpose queue that stores Int values.
Start by downloading the queue starter project. The playground will contain an empty Queue:
public struct Queue {
}
The playground also contains the code for a LinkedList (you can see this by going to View\Project Navigators\Show Project Navigator and opening Sources\LinkedList.
LinkedList works? Check out our Swift linked list tutorial, which walks you through it step by step.Enqueue
A queue needs an enqueue method. You’ll use the LinkedList implementation included in the starter project to implement your queue. Add the following between the curly braces:
// 1
fileprivate var list = LinkedList<Int>()
// 2
public mutating func enqueue(_ element: Int) {
list.append(element)
}
Here’s what you’ve done:
- You’ve added a private
LinkedListvariable that will be used to store the items in your queue. - You’ve added a method to enqueue items. This method will mutate the underlying
LinkedListso you’ve explicitly specified that by prepending themutatingkeyword in front of the method.
Dequeue
A queue also needs a dequeue method.
// 1
public mutating func dequeue() -> Int? {
// 2
guard !list.isEmpty, let element = list.first else { return nil }
list.remove(element)
return element.value
}
Here’s what you’ve done:
- You’ve added a
dequeuemethod that returns the first item in the queue. The return type isnullableto handle the queue being empty. This method will mutate the underlyingLinkedListso you’ve explicitly specified that by prepending themutatingkeyword in front of the method. - You’re using the
guardstatement handle the queue being empty. If this queue is empty, thenguardwill fail into theelseblock.
Peek
A queue also needs a peek method which returns the item at the beginning of the queue without removing it.
Try updating the implementation of Queue to include a peek method.
The solution is provided in the spoiler section down below, but try it yourself first!
[spoiler title="Solution"]
public func peek() -> Int? {
return list.first?.value
}
[/spoiler]
IsEmpty
A queue can be empty. You can add an isEmpty property that will return a value based on the underlying LinkedList:
public var isEmpty: Bool {
return list.isEmpty
}
Printing Your Queue
Let’s try out your new queue. Outside the implementation of Queue, write the following into your playground:
var queue = Queue()
queue.enqueue(10)
queue.enqueue(3)
queue.enqueue(57)
After defining the queue, try printing the queue to the console:
print(queue)
You can bring up the console by pressing the following keys in combination: Command-Shift-Y. You should see the following printed out to the console:
Queue
That isn’t very helpful. To display a more readable output string, you can make Queue adopt the CustomStringConvertable protocol. To do this, add the following just below the implementation of your Queue class:
// 1
extension Queue: CustomStringConvertible {
// 2
public var description: String {
// 3
return list.description
}
}
Here’s how the code works:
- You’ve declared an extension to your
Queueclass, and you’ve adopted theCustomStringConvertibleprotocol. This protocol expects you to implement a computed property with the namedescription, with theStringtype. - You’ve declared the
descriptionproperty. This is a computed property, a read only property that returns aString. - You’re returning the description of the underlying
LinkedList.
Now, when you call print on your Queue, you’ll get a nice representation of your list like this:
"[10, 3, 57]"
Generic Swift Queue Implementation
At this point, you’ve implemented a general-purpose queue that stores Int values, and have provided functionality to peek, enqueue and dequeue items in your Queue class.
In this section, you will use generics to abstract away the type requirement from your queue.
Update the implementation of your Queue class to the following:
// 1
public struct Queue<T> {
// 2
fileprivate var list = LinkedList<T>()
public var isEmpty: Bool {
return list.isEmpty
}
// 3
public mutating func enqueue(_ element: T) {
list.append(element)
}
// 4
public mutating func dequeue() -> T? {
guard !list.isEmpty, let element = list.first else { return nil }
list.remove(element)
return element.value
}
// 5
public func peek() -> T? {
return list.first?.value
}
}
Here’s what you’ve done:
- You’ve changed the declaration of the
Queueto take a generic typeT. - Your goal is to allow the
Queueto take in values of any type, so you’ll constrain your underlyingLinkedListto be typeTrather than aInt. - You’ve updated
enqueueto take any type. - You’ve updated
dequeueto return any type. - You’ve updated
peekto return any type.
You can fix up your test code as follows:
var queue = Queue<Int>()
queue.enqueue(10)
queue.enqueue(3)
queue.enqueue(57)
And you can even try your Queue with different types as well:
var queue2 = Queue<String>()
queue2.enqueue("mad")
queue2.enqueue("lad")
if let first = queue2.dequeue() {
print(first)
}
print(queue2)