A linked list is a linear colletion of elements in sequential order. Imagine a chain, with a start and a end, with the chain links connected to each other. A linked list can be visualized as below:
A linked list is composed of a smaller data structure usually called a Node. The node object contains the value of the element itself, and also a pointer to the next node in the chain. By utilizing node.next, you can traverse the list. The beginning of a linked list is denoted with head and the last element is tail.
In a singly-linked list, the link is established in one direction only, where the node only keeps track of the next node in the chain. This means that with a singly-linked list, you can only traverse in the direction of the tail. On the other hand, a node in a doubly-linked list keeps track of both next and previous which allows you to traverse in both directions (towards head and tail).
In this exercise, implement the following functions for the LinkedListNode and LinkedList classes:
LinkedListNodeconstructor()- Write a method that instantiates the node.
- The node takes
valueandnext.
LinkedListconstructor()- Write a method that instantiates the list.
- The instance variables
headandtailshould be set tonull.
prepend(value)- Write a method that inserts the
valueat the beginning of the linked list.
- Write a method that inserts the
append(value)- Write a method that inserts the
valueat the end of the linked list.
- Write a method that inserts the
delete(value)- Write a method that deletes the
valuein the linked list.
- Write a method that deletes the
find(value)- Write a method that returns the
nodethat contains thevalue.
- Write a method that returns the
insertAfter(value, targetValue)- Write a method that inserts the
nodeafter thenodethat contains thetargetValue.
- Write a method that inserts the
deleteHead()- Write a method that deletes the first element in the linked list.
deleteTail()- Write a method that deletes the last element in the linked list.
The most important operations are prepend/append for adding data, delete for removing data, and find for retrieving data.
Let's start by opening up a terminal window and running npm run watch. This will start our TDD framework that will automatically re-run the tests when you save any changes to your file.
- In your code editor, navigate to
/algorithms/src/data-structures/LinkedListNode.js. - In the constructor method, write
this.value = valueand save the changes. - You will see the tests run automatically in your terminal:
Jest Tip: If you need to filter by the exercise name, press
p. (presswfor the list of available commands).
The output tells you that three tests are failing:
- ✕ should create list node with value (10ms)
- ✕ should create list node with object as a value (2ms)
- ✕ should link nodes together
- ✓ should convert node to string
- ✓ should convert node to string with custom stringifier (1ms)
The code for the last two tests (toString() tests) have been provided for you in the skeleton. Your task is to make the three failing tests to pass.
- The test description says
› should create list node with value - The output tells us where the test is failing:
expect(node.next).toBeNull();. It also tells usexpect(received).toBeNull()andReceived: undefined. - In this case, the test is
expectingnode.nextto benull. However, the test receivedundefined. - Since
nextis undefined, let's update ourconstructor()inLinkedListNode.js:constructor(value, next = null) { this.value = value; this.next = next; } - When you save the file, you should see all your tests for
LinkedListNodepass! - Often, many tests can depend on the same part of the code. In this case, solving for one test case solved all others.
Now, let's open up LinkedList.js in our editor.
- A linked list should always have a
headand atail. - The test tells us:
expect(linkedList.head).toBeNull();. Let's create the instance variables:constructor() { this.head = null; this.tail = null; }
- The
prependmethod inserts the item at the beginning of the list. - Prepending an item is a simple operation:
- Create a new
Node. - Set the new
node's `next to be the current head node. - Update the
headto point at the new node.
- Create a new
- We also have to consider a case where this is the first item stored in the list. In that case, we also set the tail to the same node.
- The
appendmethod inserts the item at the end of the list. - Operations:
- Create a new
Node. - Set the tail's
nextto be the new node. - Update
tailto point at the new node.
- Create a new
- Again, take into consideration when this is the first item stored in the list.
-
The
findmethod returns the node with the target value. -
A node can be visited by utilizing a loop and
node.next. -
The following snippet traverses the entire list:
let currentNode = node; while (currentNode.next) { currentNode = node.next console.log(currentNode.value) } -
Think about how the above concept can be applied to find the target node.
- The
insertAftermethod stores theinsertValueright after the node with thevalue. - Operation:
- Create a new
Node. - Find the node with the target value.
- Set the found node's
nextto the new node. - Set new node's
nextto the found node's `next.
- Create a new
- Utilize the previously written
findmethod to find the node.
- The
deletemethod removes the first node with the specified value. - Operations:
- Traverse the list and locate the node before the target node.
- Remove the target node that is placed after the found node.
- In a linked list, you don't have to delete the actual node.
- Deleting means removing the reference to that node from the list.
- The above diagram shows that all we have to do is set the target node's previous node's
nextto point at the target node'snext. - This means that we must locate the node right before the target node. Think about how you would be able to tell when the next node will be the target node.
- Also, take into consideration if the
headortailnode is the node to be deleted.
- This is the most complex operation in a linked list. Drawing the operation on paper can help you visualize the problem. Don't hesitate to reach out to #basic-algorithms channel on Slack if you are stuck.
- The
deleteHead/Tailmethods are utility methods for common operations.
This section will be released in the future when the Big O notation tutorials are written. Please join #basic-algorithms channel for the update notifications.

