How I Taught Myself Linked Lists. Breaking down the definition of linked... | by Cleon W | Towards Data Science

Linked lists are amongst the simplest and most common data structures. If you have ever attempted to learn more about basic data structures, it is likely that you’ve come across linked lists and have read definitions similar to the following:
A linked list is a data structure where the objects are arranged in a linear order. Unlike an array, however, in which the linear order is determined by the array indices, the order in a linked list is determined by a pointer in each object.
Based on personal experience when learning about data structures, the above probably makes no sense to the absolute beginner. As such, this post aims to show that linked lists are conceptually simple by breaking down its definition in an intuitive and layman way to you, as though you were a complete beginner.
We will leave the “So what?” of studying linked lists to the end of this post, as I believe that we will be able to ask more meaningful ‘so whats’ when equipped with a better understanding of linked lists. Note that we will be referencing the above definition throughout the article.
So let’s get started.
A linked list is a data structure...
Since linked list is a type of data structure, it pays to briefly understand what is a data structure.
Simply put, a data structure is how data is stored and organised.
Then, depending on how the data is stored and organised, different operations can be applied to the data.
What differentiates data structures from each other can either be how the data is stored and organised, what can be done with and/or to the data, or both. A bulk of the problems in computer science requires some sort of data, and our need to efficiently retrieve information from the data depending on the problem type is what motivates the creation of the different data structures that we have today.
For example, a linked list stores and organises data in a linear order with the help of pointers (this is the “how data is organised”), and these pointers allow us to easily insert and remove elements without reorganising the entire data structure (this is the “what can be done”). This makes a linked list a linear data structure (as opposed to a non-linear one).
... where the objects are arranged in a linear order.
Storing elements in a linear order means organising them in a sequential order such that there is:
Only one first element and it has only one next element
Only one last element and it has only one previous element
All other elements have a previous and next element
For example, apart from linked lists, arrays are also linear data structures that store data in a linear order.
Again, whether linear or non-linear data structures are better depends on your use case. Both types have their pros and cons, as usual.
... Unlike an array, however, ...
By now, you should have noticed that linked lists are most commonly compared to arrays. What is wrong (or right) with arrays depends on your use case. As with any other data structure, an array does have its own pros and cons.
While arrays offer very fast indexed access and assignment of elements, they have fixed, immutable lengths. That means that they cannot grow or shrink, and it is impossible to append or insert items. Consequently, we must know how many elements we want to store when creating an array, which might cause certain issues depending on the problem at hand.
Dynamic arrays (e.g. Python’s list) have variable lengths and this is done by reserving additional memory space. However, inserting an element at the start of a dynamic array can be really expensive compared to inserting it at the end. This might pose as a huge blocker, again depending on the problem that you are trying to address.
Using Python’s list object, we can run the following code to illustrate this:
n = 500000example_list1 = []example_list2 = []# Slow insertion of at the front of Python listsfor i in range(0, n):    example_list1.insert(0, i)# Fast insertion of at the end of Python listsfor i in range(0, n):    example_list2.insert(i, i)
Recording and printing the time taken to completely insert 500,000 elements, we get:
Insertion at start took: 110.1042 secondsInsertion at end took: 0.1853 seconds
With a dynamic array, in order to insert an element in the first position (or first index), you would need to move all of the other elements ‘to the right’ to make room for this new element. Naturally, you can imagine that if you have an array with a large number of elements this would be really inefficient. Furthermore, there is a possibility of you needing to allocate more memory space to the array before shifting the elements.
This is where linked lists can do better.
...the order in a linked list is determined by a pointer in each object.
Pointers, pointers, pointers.
Despite both linked lists and arrays being linear data structures, a linked list maintains the linear order of its elements using pointers (as compared to the indices in arrays). The use of pointers allows us to insert or remove nodes at arbitrary positions more efficiently than we could with arrays.
In its most basic form (i.e. containing only the required attributes), linked lists are made up of:
Objects called Nodes with the attributes: (a) Item, which is assigned the data that it stores (required), (b) Next pointer, which points to the next Node in the linear order (required) and (c) Previous pointer, which points to the previous Node in the linear order (not required).A pointer to the head of the list (required)A pointer to the tail of the list (not required)
Objects called Nodes with the attributes: (a) Item, which is assigned the data that it stores (required), (b) Next pointer, which points to the next Node in the linear order (required) and (c) Previous pointer, which points to the previous Node in the linear order (not required).
A pointer to the head of the list (required)
A pointer to the tail of the list (not required)
To see how a linked list allows us to efficiently insert objects at the head and tail, we will implement a linked list with 3 nodes holding the integers 14, 5 and 22 as data in linear order. Each node has a pointer to the next node and the linked list has both a pointer to the head of the list and a pointer to its tail.
Since the position of a node in the list is stored in the pointer of the previous node, the nodes of a linked list do not necessarily have to be organised consecutively in memory. In fact, it can be stored anywhere in memory. Hence, it would look more like this:
To insert a node that carries integer 50 at the tail of the linked list, we do the following:
Create a new node with its item = 50Let its next pointer point to NoneLet the current tail node point to this new node instead of NoneReset the tail pointer of the linked list to point to this newly created node
Create a new node with its item = 50
Let its next pointer point to None
Let the current tail node point to this new node instead of None
Reset the tail pointer of the linked list to point to this newly created node
Similarly, to add an item at the head of the linked list, we do the following:
Create a new NodeLet its next pointer point to the current head of the linked listReset the head pointer of the linked list to point to this newly created node
Create a new Node
Let its next pointer point to the current head of the linked list
Reset the head pointer of the linked list to point to this newly created node
That essentially is a linked list in its simplest form.
As promised, so what?
We can see that the main benefit of a linked list as compared to a (dynamic) array is that it allows for fast insertion (and removal) of items. Unlike arrays, there is no need to restructure the entire data structure and reallocate memory for that restructuring. This stems from the use of pointers to maintain the linear order of the data, which removes the need for the data items to be stored in a consecutive manner in memory. In other words, linked lists allow the insertion and removal of items using a fixed number of operations (as listed in the steps above), regardless of the length of the list.
Using these fundamental concepts of a node, how it stores data and points to its neighbour(s), we can build other (more complicated) types of linked lists depending on our needs, such as doubly linked lists and circular linked lists.
More excitingly, understanding linked lists and their nodes can lead us to exploring and understanding other data structures and even algorithms. A linked list is one of the many ways to implement other abstract data types such as stacks, queues, hash tables and graphs, which we will sink our teeth into another day.
For the record, this is how the above singly linked list will look like in a conventional textbook, without the colours of course: