Linked Lists
Why is this important?
This workshop is important because:
- Data Structures are popular interview topics.
- Linked lists are a foundational data structure - understanding them will make it easier to understand stacks, queues, trees, graphs, and hash maps.
- The concept of a "pointer" - which stores a memory location, is common in lower-level programming languages.
What are the objectives?
After this workshop, developers will be able to:
- Describe the low-level structure of arrays and linked lists.
- Manipulate linked lists.
What are linked lists?
Linked lists store sequential (ordered) data in a series of "nodes". Each node in a linked list contains some value and a reference or "pointer" to the next node.
Every linked list has a head, which is just the first node in the list. A linked list itself is actually just storing the head node.
The very last node of a linked list, called the tail, has a null next node because nothing comes after it. Most singly linked lists don't store a reference directly to the tail, but it can make some operations smoother.
Singly Linked Lists and Arrays
####So... liked lists are like arrays?
A little! But not 100%. Let's step back and take a closer look at arrays. Their true nature may surprise you!
Arrays store data in one continuous block of computer memory. The computer sets aside just enough memory when the array is created. You can think of your computer's memory as a giant city full of identical buildings. Using an array is like renting out a bunch of adjacent buildings.
This makes it really convenient to find all the data in an array. Your computer knows where each piece of data is stored because it knows where your array's territory starts and how big each building is. Your computer can move from one location in the array to the next about as easily as you stroll down the street.
On the other hand, your computer needs to know from the start exactly how many buildings you need -- how big the array will be. And, if you ever need more space, your computer has to find a new continuous row of empty buildings big enough for you - a new block of free memory that can fit the entire array.
But wait! You've never had to worry about array size...
Totally! In lower level computer programming languages like C, you would have to. JavaScript and Ruby handle array sizing and resizing for you efficiently. That's one of the reasons we love higher level programming languages.
But! in interviews it's good to know what's happening in the background, because that's the biggest difference between arrays and linked lists.
Array / Linked List Tradeoff
Creating a linked list is a bit like renting buildings all around the city, wherever it's convenient. From there on, you just add a new building whenever you need one, wherever you can find one available. With linked lists, each building is a "node" in the list.
In our analogy, you delegate a lot! You would know the address of the headquarters (the head or first node of the linked list). In a singly linked list, every node stores a pointer that gives the memory address of the next node. This is like letting each building manager keep track of just their address and the address of the next building you own. In a doubly linked list, each node has pointers to the next and the previous node.
Pros and Cons
Linked lists don't need to be resized with one giant block of memory; they can grow with pointers to other parts of the computer's memory. You don't have to find continuous free space.
It's easier to insert into the middle of a linked list, because with an array you'd need to move every element after the insertion point over by one. It's easier with linked lists, as you'll see in the challenges.
On the other hand...
You can't quickly access a particular node in a linked list, like you can with array indices. You have to start with the head and move sequentially.
Linked lists take up a bit more space because in addition to storing the actual data, you have to store the pointers. (You have to hire building managers to keep track of where the next address is!)
It can take more time to access a full linked list, because the data living in different places can't just be read as a continuous chunk. You have to travel around the city to visit all of your buildings.
Real-world Uses
-
file systems Files are often stored in chunks, but when files grow large they may not fit in their original chunk. You can think of a file as a series of nodes with chunks of data and links to the next section of the file. (They're often actually implemented with a more complex related data structure called a B-tree.)
-
implementing stacks and queues Linked lists are a natural choice for these data structures, which need fast access to beginning or end of a list.
Base Challenges
Take a look at the starter code for a singly linked list object type and a node object type.
Each node stores data
and the next
node. The linked list stores its head
, which is a Node
.
If you haven't yet, clone this repo. Fill in the method stubs from singly_linked_list.rb to your heart's content! Methods like delete
and middle_node
are reasonable interview questions.
Stretch Challenge
These stretch challenges are harder interview questions. A hint for both: use two pointers to track two locations in the list.
-
Write a method to find the nth-from-last node of a linked list. Can you do this while only looping through the list once?
-
Cycles in linked lists (repeated nodes) can make them stop working for a lot of applications. Write a method to detect whether a linked list has a cycle in it.
Closing Thoughts
-
What is the difference between arrays and linked lists?
-
How do you loop through a linked list?
-
What is a pointer?
Further Reading
The article below goes step by step on creating a linked list and inserting items into it, in JavaScript. It might spoil some of today's solutions, but you can use this as a guide when dealing with linked lists and their properties: