Photo by Sean Stratton on Unsplash
Algorithms and Data Structures: The Fundamentals (Part I)
A brief introduction to the fundamentals of algorithms and data structures.
Introduction
Algorithms and Data Structures are such an essential part of Development and Computer Science as a whole. The majority of all programs will make use of various different data structures and algorithms to ensure that programs are as time and memory efficient as possible.
They are almost guaranteed to come up in a Software Development interview. But they can be a right head scramble at times.
This series will cover the fundamental algorithms and data structures (and all the key information) you need to know to ace all your interviews. We're beginning our series with the key data structures and their most important features.
1: Arrays vs Lists
At first glance, arrays and lists seem identical. This is possibly due very popular programming languages, such as Python, using list data structures to represent arrays.
However, even though the difference is subtle, interviewers and exam papers love to throw this question in the mix to try and catch people out.
Definition: An array is a static data structure, where the size (number of elements) is fixed from declaration and cannot change throughout the program. In an array, the type of each element must be the same.
Definition: A list is a dynamic data structure, where elements of any type can be added and removed at any point in the program regardless of whether the size of the list changes.
Most of programming languages don't force the rules of arrays upon users, and often there is no way to differentiate between an array and a list in code. Standards need to be maintained by coders themselves.
In JavaScript, we can declare an array in multiple ways:
// 1) use new Array() to create an array size 20, where every element is the number 29.
const myArray = new Array(20).fill(29)
// 2) directly declare the array/list
const myOtherArray = ["๐จ", "๐ป", "๐"]
The first option with `myArray` upholds the standards of arrays much more clearly, whereas the second option can easily be confused for a list.
Universally, we can access elements in an array or a list through their index.
Definition: An index of an element is simply the position of the element in the array/list relative to the first element (which has index 0).
console.log(myOtherArray[0])
<< "๐จ"
console.log(myOtherArray[1])
<< "๐ป"
console.log(myOtherArray[2])
<< "๐"
This `[index]` notation is widely used across programming languages.
2: Linked Lists
A Linked List is a special case of the list data structure.
Definition: A linked list is a dynamic data structure , where each element (node) consists of both data and a pointer to the next element in the list.
This diagram makes visualising a linked list much easier:
Here we have four nodes.
The data is the letter values in each node. And the pointers can be seen from the arrows.
If we begin traversing the list from A, we'll read A -> C -> B -> D.
This diagram isn't quite accurate because we need to label a head node and a tail node.
Head node: the 1st node in the list.
Tail node: the last node in the list. This node's pointer will always point to null.
3: Stacks
Definition: Stacks are a data structure that follow the LIFO principle to retrieve data.
LIFO: Last In First Out
The last (most recent) element entered into the Stack, will be the first one to be removed.
Think of the elements as a tower of bricks. In order to get the next element in the easiest way, you would take the brick on top of the pile, rather than at the bottom.
As you can see, we define also two key elements in the stack: head and tail.
Head always points to the element that we will remove next.
Tail points to the last element in the stack.
The standard method for removing from a stack is called .pop()
and the standard method for adding to a stack is called .push()
.
We can see the implementation of these in JavaScript:
let myStack = [16, 7, 9, 12]
myStack.pop()
myStack.push(29)
console.log(myStack)
<< [16, 7, 9, 29]
Not all languages have these methods built in exactly as the name. But they are easy to implement yourself. In fact, many implementations of a stack can be done using Object-Oriented Programming, with a class.
The most famous use of a Stack is the back button on a web browser. We need to access the last site visited.
4: Queues
A Queue can be considered as the inverse pair to a Stack. We have the same functionality, but reverse order for accessing elements.
Definition: A Queue is a data structure that follows the FIFO principle to retrieve data.
FIFO: First in First Out
The first element entered into the Queue is the first element to be removed.
Exactly the same as a queue of people in a coffee shop: the first person there is the first person to get their coffee.
We can visualise this in exactly the same way as a Stack, but swap the head and tail pointers.
And implementing a Queue in JavaScript looks like this:
let myQueue = [16, 7, 9, 12]
myQueue.shift()
myQueue.push(10)
console.log(myQueue)
<< [7, 9, 12, 10]
The formal methods for a Queue are:
.enqueue()
to add an element to the Queue.dequeue()
to remove an element from the Queue
However, unless written as helper functions or methods of a class, most programming languages won't have these inbuilt.
The biggest use of a Queue data structure is when organising documents to be printed. The first job that arrives at the printer is the first job to be executed.
Table of Comparison
Array | List | Linked List | Stack | Queue | |
Static/Dynamic | Static | Dynamic | Dynamic | Either | Either |
Type | All elements must be the same type | Don't have to be the same type | Either (usually same type) | Either (usually same type) | Either (usually same type) |
Access rules | Any | Any | Through pointers | LIFO | FIFO |
Data stored in order of entry | Yes | Yes | No | Yes | Yes |
Conclusion
And that's part one!
I hope you found this a useful introduction to the key features of some fundamental data structures. Let me know what you think in the comments below!