Single Linked List - TypeScript

Typescript Data Structures: Linked List

In the vast expanse of data structures available to developers, the LinkedList holds a unique place. Known for its efficiency in insertion and deletion operations, it’s a staple in algorithm design and application development. This post explores how to implement a LinkedList in TypeScript, bringing together the efficiency of this data structure with the strong typing and object-oriented features of TypeScript.

Understanding LinkedLists

Before diving into the code, let’s grasp the basics of a LinkedList. At its core, a LinkedList is a collection of nodes, where each node contains data and a reference (or a pointer) to the next node in the sequence. This structure allows for efficient additions and deletions as it avoids the necessity of reindexing elements, a common performance bottleneck in array manipulations.

Implementing Nodes in TypeScript

The foundation of our LinkedList is the node. Each node will store a value and a pointer to the next node. Here’s how we define it in TypeScript:

class Node {
    val: number;
    next: Node | null;

    constructor(val: number) {
        this.val = val; // The value stored in the node
        this.next = null; // Pointer to the next node, initially null
    }
}

This Node class is straightforward: it initializes with a value and sets the pointer to the next node as null.

The MyLinkedList Class

With our nodes defined, we next construct the LinkedList class, MyLinkedList. This class will manage our nodes and provide methods to interact with the list.

Constructor and Properties
class MyLinkedList {
    head: Node | null;
    tail: Node | null;
    size: number;

    constructor() {
        this.head = null;
        this.tail = null;
        this.size = 0;
    }
}

Our LinkedList starts empty, signified by a null head and tail, with a size of 0.

Adding Elements

We provide three methods to add elements to our list: at the head, at the tail, and at a specific index.

  • addAtHead(val: number): Inserts a new node with the provided value at the beginning of the list.
  • addAtTail(val: number): Appends a new node with the provided value at the end of the list.
  • addAtIndex(index: number, val: number): Inserts a new node at the specified index.

Each method updates the head, tail, and size properties accordingly to maintain the integrity of the list.

Retrieving and Deleting Elements
  • get(index: number): Returns the value of the node at the specified index.
  • deleteAtIndex(index: number): Removes the node at the specified index.

These methods ensure our LinkedList is dynamic, allowing retrieval and modification post-initialization.

Conclusion

Implementing a LinkedList in TypeScript is a rewarding exercise that deepens our understanding of both TypeScript and fundamental data structures. This guide has walked you through creating a flexible, type-safe LinkedList, suitable for various applications requiring efficient insertions and deletions. Whether you’re building a complex application or brushing up on data structures, the combination of TypeScript and LinkedLists is a powerful tool in your development arsenal.

Next Steps

Now that you’ve implemented a basic LinkedList, consider extending its functionality. Try adding methods to reverse the list, detect cycles, or merge two sorted lists. Each addition will not only improve your understanding of LinkedLists but also enhance your problem-solving skills in TypeScript.

Full Code

class Node {
    val: number;
    next: Node | null;

    constructor(val: number) {
        this.val = val; // The value stored in the node
        this.next = null; // Pointer to the next node, initially null
    }
}

class MyLinkedList {
    head: Node | null;
    tail: Node | null; // Pointer to the last node
    size: number; // The number of nodes in the list

    constructor() {
        this.head = null; // Initialize the head to null for an empty list
        this.tail = null; // Likewise for the tail
        this.size = 0; // Start with a list size of 0
    }

    // Adds a node at the front of the list
    addAtHead(val: number): void {
        const newNode = new Node(val);
        newNode.next = this.head;
        this.head = newNode;
        if (this.size === 0) {
            this.tail = newNode; // If the list was empty, this new node is also the tail
        }
        this.size++;
    }

    // Adds a node at the end of the list
    addAtTail(val: number): void {
        const newNode = new Node(val);
        if (this.size === 0) {
            this.head = newNode;
            this.tail = newNode;
        } else {
            this.tail.next = newNode;
            this.tail = newNode;
        }
        this.size++;
    }

    // Adds a node at the specified index
    addAtIndex(index: number, val: number): void {
        if (index < 0 || index > this.size) return; // Check for valid index
        if (index === 0) {
            this.addAtHead(val);
            return;
        }
        if (index === this.size) {
            this.addAtTail(val);
            return;
        }

        const newNode = new Node(val);
        let current = this.head;
        for (let i = 0; i < index - 1; i++) { // Iterate to the node before the desired index
            current = current.next;
        }
        newNode.next = current.next;
        current.next = newNode;
        this.size++;
    }

    // Gets the value of the node at the specified index
    get(index: number): number {
        if (index < 0 || index >= this.size) return -1; // Check for valid index
        let current = this.head;
        for (let i = 0; i < index; i++) {
            current = current.next;
        }
        return current.val;
    }

    // Deletes the node at the specified index
    deleteAtIndex(index: number): void {
        if (index < 0 || index >= this.size) return; // Check for valid index
        if (index === 0) {
            this.head = this.head.next;
            if (index === this.size - 1) { // If there was only one node, update tail to null
                this.tail = null;
            }
        } else {
            let current = this.head;
            for (let i = 0; i < index - 1; i++) {
                current = current.next;
            }
            current.next = current.next.next;
            if (index === this.size - 1) { // If deleting the last node, update tail
                this.tail = current;
            }
        }
        this.size--;
    }
}

Also this one can let you pass the Leetcode question: 707. Design Linked List

这个博客讲的就是TypeScript的单链表的实现方法啦,可以看看 抄抄,这个能让你直接通过Leetcode的第707题

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.