Find Length of a Linked List in JavaScript



To find the length of a linked list in JavaScript, we need to count how many nodes are present. A linked list is made up of nodes, where each node contains data and a reference to the next node. The length is determined by starting at the head and counting each node until the end of the list. If the list is empty, the length should be 0.

Our task is to write a JavaScript program that calculates the length of a linked list . In other words, we need to find out how many nodes are in the list.

Example

Let's consider the following example linked list:

1 -> 3 -> 7 -> 11 -> 15 -> null
The length of this list is 5 since there are five nodes.

Approaches to Find Linked List Length

There are several approaches we can use to determine the length of a linked list. Below, we explain each approach.

Traverse the List Iteratively

In this method, we define a linked list using a class to represent its structure. We then create a function that traverses the list starting from the head node. Using a while loop, we count each node as we move through the list, continuing until we reach the end (when the next pointer is null).

Example

Here's an implementation of this approach. The LinkedList class has a push method to add new nodes and a getLength method to count the nodes iteratively using a while loop.

class Node {
   constructor(value) {
       this.value = value;
       this.next = null;
   }
}

class LinkedList {
   constructor() {
       this.head = null;
   }

   // Method to push new values to the list
   push(value) {
       const newNode = new Node(value);
       if (!this.head) {
           this.head = newNode;
       } else {
           let current = this.head;
           while (current.next) {
               current = current.next;
           }
           current.next = newNode;
       }
   }

   // Method to find the length of the list iteratively
   getLength() {
       let length = 0;
       let current = this.head;
       while (current !== null) {
           length++;
           current = current.next;
       }
       return length;
   }
}

// Example usage
const list = new LinkedList();
list.push(1);
list.push(3);
list.push(7);
list.push(11);
list.push(15);

console.log(`The length of the list is: ${list.getLength()}`);  // Output: The length of the list is: 5

Output

The length of the list is: 5

Time Complexity: O(n) because we traverse all n nodes.

Space Complexity: O(1) since only a fixed amount of space is used for the counter.

Recursive Approach

In the recursive approach, we define a function that calls itself on the next node until it reaches the end (null). Once the end is reached, the function starts returning the counts.

Example

Here's a JavaScript code where recursion calculates the length of the linked list. The function calls itself on the next node until the base case (null) is reached, then returns and adds up the length.

class Node {
    constructor(value) {
        this.value = value;
        this.next = null;
    }
}

class LinkedList {
    constructor() {
        this.head = null;
    }

    push(value) {
        const newNode = new Node(value);
        if (!this.head) {
            this.head = newNode;
        } else {
            let current = this.head;
            while (current.next) {
                current = current.next;
            }
            current.next = newNode;
        }
    }

    getLengthRecursive(node) {
        if (node === null) {
            return 0;
        }
        return 1 + this.getLengthRecursive(node.next);
    }
}

// Example usage
const list = new LinkedList();
list.push(1);
list.push(3);
list.push(7);
list.push(11);
list.push(15);

console.log(`The length of the list is: ${list.getLengthRecursive(list.head)}`);  // Output: The length of the list is: 5

Output

The length of the list is: 5

Time Complexity: O(n) because we visit each of the n nodes in the list once.

Space Complexity: O(n) because the amount of memory used grows with the length of the list due to the recursive calls.

Using a Helper Function (Non-Recursive)

In this approach, we use a helper function to traverse the linked list and count the nodes recursively, providing clearer separation of concerns.

Example

Here's an example code where we use a helper function to traverse the list, recursively calling itself on the next node while increasing the count until the end of the list is reached.

   class Node {
    constructor(value) {
        this.value = value;
        this.next = null;
    }
}

class LinkedList {
    constructor() {
        this.head = null;
    }

    // Method to push new values to the list
    push(value) {
        const newNode = new Node(value);
        if (!this.head) {
            this.head = newNode;
        } else {
            let current = this.head;
            while (current.next) {
                current = current.next;
            }
            current.next = newNode;
        }
    }

    // Helper function to find the length of the list
    getLengthHelper() {
        const length = this.countNodes(this.head, 0);
        console.log(`The length of the list is: ${length}`);
        return length;
    }

    // Recursive helper function
    countNodes(node, count) {
        if (node === null) {
            return count;
        }
        return this.countNodes(node.next, count + 1);
    }
}

// Example usage
const list = new LinkedList();
list.push(1);
list.push(3);
list.push(7);
list.push(11);
list.push(15);

// Display the length of the list
list.getLengthHelper();  // Output: The length of the list is: 5

Output

The length of the list is: 5

Time Complexity: O(n) because each node is processed once, similar to the recursive approach.

Space Complexity: O(n) because the recursive call stack grows with the length of the list.

Using a Length Property (Optimized Approach)

If we have control over the linked list implementation, we can optimize the process by maintaining a length property that is updated whenever nodes are added or removed. This allows constant-time retrieval of the length.

Example

Here, we maintain a length property in the linked list class. Every time we add a new node, we increment the length. When retrieving the length, we can simply return the stored value in constant time.

class Node {
    constructor(value) {
        this.value = value;
        this.next = null;
    }
}

class LinkedList {
    constructor() {
        this.head = null;
        this.length = 0;  // Initialize length property
    }

    // Method to push new values to the list
    push(value) {
        const newNode = new Node(value);
        this.length++;  // Increment length property
        
        if (!this.head) {
            this.head = newNode;
            return;
        }

        let current = this.head;
        while (current.next) {
            current = current.next;
        }
        current.next = newNode;
    }

    // Method to get the length of the list
    getLength() {
        return this.length;  // Return the length directly
    }
}

// Example usage
const list = new LinkedList();
list.push(1);
list.push(3);
list.push(7);
list.push(11);
list.push(15);

// Display the length of the list
console.log(`The length of the list is: ${list.getLength()}`);  // Output: The length of the list is: 5

Output

The length of the list is: 5

Time Complexity: O(1) because we simply update the length property each time a new node is added, without needing to traverse the list.

Space Complexity: O(1) because we only use a fixed amount of extra space for the length property and other variables.

Complexity Comparison

Here is a comparison of time and space complexity for all the approaches discussed:

Approach Time Complexity Space Complexity
Iterative Approach O(n) O(1)
Recursive Approach O(n) O(n) (due to call stack)
Helper Function Approach O(n) O(n) (due to call stack)
Using a Length Property O(n) (for 'push()') / O(1) (for 'getLength()') O(1)

Conclusion

There are several ways to find the length of a linked list, each with its own trade-offs. The iterative approach is simple and space-efficient, while recursion uses more memory. Maintaining a length property provides quick access but requires extra management. Generally, the iterative approach is preferred, but keeping track of the length is better for frequent queries.

Practice and learn from a wide range of JavaScript examples, including event handling, form validation, and advanced techniques. Interactive code snippets for hands-on learning.
Updated on: 2025-01-20T17:41:36+05:30

392 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements