Implementing Linked List In Scala

In Scala, if you wonder why its standard library doesn’t come with a data structure called LinkedList, you may have overlooked. The collection List is in fact a linked list — although it often appears in the form of a Seq or Vector collection rather than the generally “mysterious” linked list that exposes its “head” with a hidden “tail” to be revealed only iteratively.

Our ADT: LinkedNode

Perhaps because of its simplicity and dynamicity as a data structure, implementation of linked list remains a popular coding exercise. To implement our own linked list, let’s start with a barebone ADT (algebraic data structure) as follows:

If you’re familiar with Scala List, you’ll probably notice that our ADT resembles List and its subclasses Cons (i.e. ::) and Nil (see source code):

Expanding LinkedNode

Let’s expand trait LinkedNode to create class methods insertNode/deleteNode at a given index for inserting/deleting a node, toList for extracting contained elements into a List collection, and toString for display:

Note that LinkedNode is made covariant. In addition, method insertNode has type A as its lower type bound because Function1 is contravariant over its parameter type.

Recursion and pattern matching

A couple of notes on the approach we implement our class methods with:

  1. We use recursive functions to avoid using of mutable variables. They should be made tail-recursive for optimal performance, but that isn’t the focus of this implementation. If performance is a priority, using conventional while-loops with mutable class fields elem/next would be a more practical option.
  2. Pattern matching is routinely used for handling cases of Node versus EmptyNode. An alternative approach would be to define fields elem and next in the base trait and implement class methods accordingly within Node and EmptyNode.

Finding first/last matching nodes

Next, we add a couple of class methods for finding first/last matching nodes.

Reversing a linked list by groups of nodes

Reversing a given LinkedNode can be accomplished via recursion by cumulatively wrapping the element of each Node in a new Node with its next pointer set to the Node created in the previous iteration.

Method reverseK reverses a LinkedNode by groups of k elements using a different approach that extracts the elements into groups of k elements, reverses the elements in each of the groups and re-wraps each of the flattened elements in a Node.

Using LinkedNode as a Stack

For LinkedNode to serve as a Stack, we include simple methods push and pop as follows:

Addendum: implementing map, flatMap, fold

From a different perspective, if we view LinkedNode as a collection like a Scala List or Vector, we might be craving for methods like map, flatMap, fold. Using the same approach of recursion along with pattern matching, it’s rather straight forward to crank them out.

Putting everything together

Along with a few additional simple class methods and a factory method wrapped in LinkedNode‘s companion object, below is the final LinkedNode ADT that includes everything described above.

A cursory test-run …

3 thoughts on “Implementing Linked List In Scala

  1. Pingback: Scala Binary Search Tree | Genuine Blog

  2. luqmaan s

    In the implementation of the insertNode method for the LinkedNode class, what is the purpose of the condition if (i < idx) and why does it return EmptyNode in that case?

    Reply
    1. Leo Cheung Post author

      Thanks for the comment and sorry for the late reply. Calling method insertNode(x, idx) represents a request to insert a node with value x as the (idx+1)-th node. For instance, insertNode(‘a’, 4) means the intention to insert a node with value ‘a’ as the 5th node. Now, if the original linked list has less than 4 nodes, it’s impossible to insert a 5th node. Thus, as the inner loop reaches the tail end (i.e. EmptyNode), i would still be less than idx, and therefore the loop should exit early with no change (i.e. EmptyNode).

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *