Contents

Understanding Linked List and Implementation in Java

   Aug 10, 2023     16 min read

What is Linked List??

A linked list is another linear data structure that stores data in a ListNode, and the ListNode has another address that points to its next ListNode.

How to represent a LinkedList?

using the head of the Linked List ListNode head
that means all Linked List Interview Problem is actually traversal problem. Because If we have the head, we can basically extract all the data afterward.

How to traverse a LinkedList?

we dont wnat to lose the address of the head, because we wont be able to visit it afterward. so, we create a variable that allow us traverse the linked list.

ListNode cur = head;
while (cur != null) {
    cur = cur.next;
}

What problems do we need to be extra cautious?

  1. Null-pointer exception, since linked list is using pointer to traverse the list.
  2. Losing the value of head. head = head.next -> will lead to lose the head pointer!

Singly Linked List Implementation

API to Implement:\

  1. get(int index)/searchByValue
  2. addHead/addTail/addIndex
  3. deleteHead/deleteTail/deleteByIndex
public SinglyLinkedList class {
    // how to print a node?
    // if you put System.out.println(new ListNode(1)) -> it will pops up error.
    // just like you want to ompare ListNode(1) && ListNode(2)
    // since they all extend the class Object in Java
    // you have to override the toString method / compare method in order to directly
    // print it out or compare it.

    static class ListNode {
        int value;
        ListNode next;
        public ListNode(int value) {
            this.value = value;
        }
        @Override
            public String toString() {
            return value + “ -> “;
        }
    }

    // field
    ListNode head;
    int size;
    public SinglyLinkedList() {
        head = null;
        size = 0;
    }

    // get the value of the index node, index range from 0 to n - 1
    public Integer get(int index) {
        if (index < 0 || index >= size) {
            throw exception;
        }
        ListNode cur = head;
        for (int i = 0; i < index; i++) {
            cur = cur.next;
        }
        return cur.value;
    }

    // return the firstNode that has target value
    public ListNode searchByValue(int value) {
        ListNode cur = head;
        while (cur != null) {
            if (cur.value == value) {
                return cur;
            }
            cur = cur.next;
        }
        return cur; // null
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public int getSize() {
        return size;
    }

    public void printLinkedList() {
        ListNode cur = head;
        while (cur != null) {
            System.out.println(cur); //We implement toString.
            cur = cur.next
        }
    }

    public void addHead(int value) {
        ListNode newHead = new ListNode(value);
        newHead.next = head;
        head = newHead;
        size++;
    }

    public void addTail(int value) {
        if (head == null) {
            addHead(value);
        }
        ListNode cur = head;
        while (cur.next != null) {
            cur = cur.next;
        }
        cur.next = new ListNode(value);
        size++;
    }

    public void addIndex(int index, int value) {
        if (index < 0 || index >= size) {
            return;
        }
        if (index == 0) {
            addHead(value);
        } else if (index == size) {
            addTail(value);
        } else {
            ListNode cur = head;
            for (int i = 0; i < index; i++) {
                cur = cur.next;
            }
            ListNode next = cur.next;
            cur.next = new ListNode(value);
            cur = cur.next;
            cur.next = next;
            size++;
        }
    }

    public void deleteHead() {
        if (head == null) {
            return;
        }
        head = head.next;
        size–;
    }

    public void deleteTail() {
        if (head == null) {
            return;
        }
        if (head.next == null) {
            deleteHead();
            return;
        }
        ListNode cur = head;
        while (cur.next.next != null) {
            cur = cur.next;
        }
        cur.next = null;
        size--;
    }

    public void deleteAtIndex(int index) {
        if (index < 0 || index >= size) {
            return;
        }
        if (index == 0) {
            deleteHead();
            return;
        } else if (index == size - 1) {
            deleteTail();
            return;
        } else {
            ListNode prev = head;
            for (int i = 0; i < index - 1; i++) {
                prev = prev.next;
            }
            prev.next = prev.next.next;
            size--;
        }
    }

}

Doubly Linked List Implementation

The only difference between Doubly Linked List and Singly Linked List is adding and deleting.

public DoublyLinkedList class {

	static class ListNode {
        int value;
        ListNode next;
        ListNode prev;
        public ListNode(int value) {
            this.value = value;
        }
        @Override
        public String toString() {
            return <- + value +  -> ;
        }
    }

    // field
    ListNode head;
    int size;
    public DoublyLinkedList() {
        head = null;
        size = 0;
    }
    //基本上改跟查 的Code是完全不需要變化
    // get the value of the index node, index range from 0 to n - 1
    public Integer get(int index) {
        if (index < 0 || index >= size) {
            throw exception;
        }
        ListNode cur = head;
        for (int i = 0; i < index; i++) {
            cur = cur.next;
        }
        return cur.value;
    }

    // return the firstNode that has target value
    public ListNode searchByValue(int value) {
        ListNode cur = head;
        while (cur != null) {
        if (cur.value == value) {
            return cur;
        }
        cur = cur.next;
        }
        return cur; // null
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public int getSize() {
        return size;
    }

    public void addHead(int value) {
        ListNode newHead = new ListNode(value);
        //多左一句
        if (head != null) {
            head.prev = newHead;
        }
        newHead.next = head;
        head = newHead;
        size++;
    }

    //増 跟刪除都只係改動左連pointer的方法.
    public void addTail(int value) {
        if (head == null) {
            addHead(value);
        }
        ListNode cur = head;
        while (cur.next != null) {
            cur = cur.next;
        }
        ListNode newHead = new ListNode(value);
        cur.next = newHead;
        newHead.prev = cur;
        size++;
    }

    public void addIndex(int index, int value) {
        if (index < 0 || index >= size) {
            return;
        }
        if (index == 0) {
            addHead(value);
        } else if (index == size) {
            addTail(value);
        } else {
            ListNode cur = head;
            for (int i = 0; i < index; i++) {
                cur = cur.next;
            }
            ListNode next = cur.next;
            ListNode newNode = new ListNode(value);
            cur.next = newNode;
            newNode.prev = cur;

            newNode.next = next;
            next.prev = newNode;
            size++;
        }
    }

    public void deleteHead() {
        if (head == null) {
            return;
        }
        head = head.next;
        head.prev = null;
        size;
    }

    public void deleteTail() {
        if (head == null) {
            return;
        }
        if (head.next == null) {
            deleteHead();
            return;
        }
        ListNode cur = head;
        while (cur.next.next != null) {
            cur = cur.next;
        }
        cur.next.prev = null;
        cur.next = null;
        size--;
    }

    public void deleteAtIndex(int index) {
        if (index < 0 || index >= size) {
            return;
        }
        if (index == 0) {
            deleteHead();
            return;
        } else if (index == size - 1) {
            deleteTail();
            return;
        } else {
            ListNode prev = head;
            for (int i = 0; i < index - 1; i++) {
                prev = prev.next;
            }
            ListNode delete = prev.next;
            ListNode next = delete.next;

            delete.prev = null;
            delete.next = null;

            prev.next = next;
            next.prev = prev;

            size--;
        }
    }
}

Circular Linked List Implementation

The only difference between SinglyLinkedList and CircularLinkedList is the terminate condition in the while loop, and always look for the tail in adding and deleting head/tail.

public CircularLinkedList class {
    static class ListNode {
        int value;
        ListNode next;
        public ListNode(int value) {
            this.value = value;
        }
        @Override
        public String toString() {
            return value +  -> ;
        }
    }

    ListNode head;
    int size;
    public CircularLinkedList () {
        head = null;
        size = 0;
    }

    // get the value of the index node, index range from 0 to n - 1
    public Integer get(int index) {
        if (index < 0 || index >= size) {
            throw exception;
        }
        ListNode cur = head;
        for (int i = 0; i < index; i++) {
            cur = cur.next;
        }
        return cur.value;
    }

    // return the firstNode that has target value
    public ListNode searchByValue(int value) {
        ListNode cur = head;
        while (cur != head) {
            if (cur.value == value) {
                return cur;
            }
            cur = cur.next;
        }
        return null; // null
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public int getSize() {
        return size;
    }

    public void addHead(int value) {
        ListNode newHead = new ListNode(value);
        newHead.next = head;
        ListNode cur = head;
        while (cur.next != head) {
            cur = cur.next;
        }
        cur.next = newHead;
        head = newHead;
        size++;
    }

    public void addTail(int value) {
        if (head == null) {
            addHead(value);
        }
        ListNode cur = head;
        while (cur.next != head) {
            cur = cur.next;
        }
        cur.next = new ListNode(value);
        cur = cur.next;
        cur.next = head;
        size++;
    }

    public void addIndex(int index, int value) {
        if (index < 0 || index >= size) {
            return;
        }
        if (index == 0) {
            addHead(value);
        } else if (index == size) {
            addTail(value);
        } else {
            ListNode cur = head;
            for (int i = 0; i < index; i++) {
                cur = cur.next;
            }
            ListNode next = cur.next;
            cur.next = new ListNode(value);
            cur = cur.next;
            cur.next = next;
            size++;
        }
    }

    public void deleteHead() {
        if (head == null) {
            return;
        }
        ListNode cur = head;
        // find the last pointer;
        while (cur.next != head) {
            cur = cur.next;
        }
        head = head.next;
        cur.next = head;
        size;
    }

    public void deleteTail() {
        if (head == null) {
            return;
        }
        if (head.next == null) {
            deleteHead();
            return;
        }
        ListNode cur = head;
        while (cur.next.next != head) {
            cur = cur.next;
        }
        cur.next = head;
        size--;
    }

    public void deleteAtIndex(int index) {
        if (index < 0 || index >= size) {
            return;
        }
        if (index == 0) {
            deleteHead();
        return;
        } else if (index == size - 1) {
            deleteTail();
        return;
        } else {
            ListNode prev = head;
            for (int i = 0; i < index - 1; i++) {
                prev = prev.next;
            }
            prev.next = prev.next.next;
            size--;
        }
    }
}

More Practice Questions

Linked List normal operation:

Problem NumberProblemSolution
1Insert In Sorted Linked List 
2Merge Two Sorted Lists 
3Remove Linked List Elements 
4Middle of the Linked List 
5Linked List Cycle 

Linked List Removal

Problem NumberProblemSolution
1Delete Node in a Linked List 
2Delete the Middle Node of a Linked List 
3Remove Nth Node From End of List 

Linked List Reverse

Problem NumberProblemSolution
1Reverse Linked List 
2Reverse Linked List II 
3Swap Nodes in Pairs 

Linked List Math Operation

Problem NumberProblemSolution
1Add Two Numbers 
2Add Two Numbers II 
3Plus One Linked List 
4Add Two Polynomials Represented as Linked Lists 

Linked List Combinations:

Problem NumberProblemSolution
1Palindrome Linked List 
2Partition List 
3 Reorder List 

Linked List Sorting:

Problem NumberProblemSolution
1 Merge Sort List 
2Insertion Sort Linked List 
3Selection Sort Linked List 
3Quick Sort Linked List