Thursday, February 20, 2014

Link list Implementation in Java

linked list is a data structure consisting of a group of nodes which together represent a sequence. Under the simplest form, each node is composed of a data and a reference (in other words, a link) to the next node in the sequence. This structure allows for efficient insertion or removal of elements from any position in the sequence.

Singly-linked-list.svg
A linked list whose nodes contain two fields: an integer value and a link to the next node. The last node is linked to a terminator used to signify the end of the list.

Linked lists are among the simplest and most common data structures. They can be used to implement several other common abstract data types, including lists (the abstract data type), stacks, queues, associative arrays.

Sections in this post: 
  1. Link List Interface
  2. Link List Node
  3. Implementation

Link List Interface

Below is my Link List Interface. It is not at  all mandatory to write Interface for link list . I have written so as to make code more understandable and  to follow good code writing practices.

public interface LLInterface {
 /*
  * different overloaded insert
  */
 public boolean insertAtStart(Node nodeToInsert);
 public boolean insertAtStart(int data);
 public boolean insertAtEnd(Node nodeToInsert);
 public boolean insertAtEnd(int data);
 public boolean insert(Node nodeToInsert, int loc);
 public boolean insert(int data, int loc);

 /*
  * different overloaded delete
  */
 public Integer deleteFirst();
 public Integer deleteLast();
 public Integer delete(int loc);
 public boolean deleteThis(int data);

 /*
  * ADT method to know if list is empty
  * we will be using this method at many places such as
         * before deleting a node to make sure list is already not empty
  */
 public boolean isEmpty();

 /*
  * ADT method to print entire list
  *
  */
 public void printList(Node head);


 /* ADT method to get number of nodes present after the given node.
        *If head is passed as argument then it will return size of list
         *This method should be avoided at places such as,
         *to validate given insertion or deletion location as it
         *internally traverse complete list once.
  */
 public int getSize(Node head);
}


Link List Node

In Link list data is stored in nodes. therefore let's see how to implement a node. For the sake of simplicity I am considering nodes having only integer values but this can be changed easily.

public class Node {

    // data variable will hold integer
    private int data;

    // Reference(Pointer) to next node
    private Node next;

    public Node(int data) {
        super();
        this.data = data;
        this.next = null;
    }

    public Node() {
        super();
    }
    /*
     * Getter and setters
     */

    public int getData() {
        return data;
    }

    public void setData(int data) {
        this.data = data;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }
}


Implementation

Now lets see how to implement link list. Whenever I am saying link list I am referring to singly link list. refer my other posts for Doubly link list and circular link list .

public class SLL implements LLInterface {

    private Node head;

    @Override
    public boolean insertAtStart(Node nodeToInsert) {
       /* Check if node is not null else return
        * We add this check as there can be situation where object is set
        * to null or some one has used default constructor make the node
        * object etc.
        */

        if (nodeToInsert == null) {
            System.out.println("Node you are trying to insert is null");
            return false;
        }

        // check if list is empty then set node as head

        if (isEmpty()) {
            head = nodeToInsert;
        }

        // make nodeToInsert as head and head as second
        // node(nodeToInsert-->head-->....)

        else {
            nodeToInsert.setNext(head);
            head = nodeToInsert;
        }
        return true;
    }

    @Override
    public boolean insertAtStart(int data) {

        /*
         * we can have two approaches to get new node
         * 
         * First Approach: Use default constructor and then set values
         * using setters
         * Node nodeToInsert = new Node();
         * nodeToInsert.setData(data);
         * nodeToInsert.setNext(null);
         *
         * Second approach: Use overloaded constructor of Node class
         */

        Node nodeToInsert = new Node(data);

        /* As we already have a method to insert node at beginning having
         * node object as parameter we will just call that
         * else we can add all the code of that method here itself
         */

        return insertAtStart(nodeToInsert);
     }

    @Override
    public boolean insertAtEnd(Node nodeToInsert) {

        /* Check if node is not null else return
         * We add this check as there can be situation where object 
        * is set to null or one has used default constructor make the node
        * object etc.
         */

        if (nodeToInsert == null) {

            System.out.println("Node you are trying to insert is null");
            return false;
        }

        // Check if list is empty then set node as head

        if (isEmpty()) {

            head = nodeToInsert;
            return true;
        }

        Node currentNode = head;
        while (currentNode.getNext() != null) {
            currentNode = currentNode.getNext();
        }

        currentNode.setNext(nodeToInsert);
        return true;
    }

    @Override
    public boolean insertAtEnd(int data) {

        /*
         * we can have two approaches to get new node 

         * First Approach: Use default constructor and then set

         * values using setters 

         * Node nodeToInsert = new Node(); 
         * nodeToInsert.setData(data);
         * nodeToInsert.setNext(null);
         * 
         * Second approach: Use overloaded constructor of Node class
         */

        Node nodeToInsert = new Node(data);

        /* As we already have a method to insert node at end having
         * node object as parameter we will just call that
         * else we can add all the code of that method here itself
         */
        
         return insertAtEnd(nodeToInsert);
    }

    @Override
    public boolean insert(Node nodeToInsert, int loc) {

        /* Check if node is not null else return
         * We add this check as there can be situation where
         * object is set to null or some one has used default constructor
         * make the node object etc.
         */
         if (nodeToInsert == null) {

            System.out.println("Node you are trying to insert is null");
            return false;
        }

        /* validate given location to add node, we wont check with list
         * size here as it internally traverse complete list once
         */
         if (loc < 1) {
           System.out.println("Invalid Location specified to insert node");
           return false;
        }

        if (loc == 1) {
            insertAtStart(nodeToInsert);
        } else {

            Node currentNode = head;

            /* Now we will reach the required location so that we can add
             * node there.Note that we will stop one place before we want
             * to add node and keep in mind current node is already at head
             * e.g. if we want to add new node at location five, then we
             * will traverse till node four.
             * We will also check whether current node is not null
             * as location given can be more then list size
             */
            
             for (int i = 0; i < loc - 2 && currentNode != null; i++) {
                currentNode = currentNode.getNext();
            }

          if (currentNode == null) {
            System.out.println("Invalid Location specified to insert node");
            return false;
          }

            /* Now we need to insert new node at this location.
             * So we make new node's next to point to current node's next
             * and current node will point to new node.
             * Note that order is important here.
             */
            nodeToInsert.setNext(currentNode.getNext());
            currentNode.setNext(nodeToInsert);

            return true;
        }

        return false;
    }

    @Override
    public boolean insert(int data, int loc) {

        /*
         * we can have two approaches to get new node
         *
         * First Approach: Use default constructor and
         * then set values using setters
         *
         * Node nodeToInsert = new Node();
         * nodeToInsert.setData(data);
         * nodeToInsert.setNext(null);
         * 
         * Second approach: Use overloaded constructor of Node class
         */

        Node nodeToInsert = new Node(data);

        /* As we already have a method to insert node at end
         * having node object as parameter we will just call that
         * else we can add all the code of that method here itself 
         */

        return insert(nodeToInsert, loc);
    }

    @Override
    public Integer deleteFirst() {

        // Check if list is already Empty

        if (isEmpty()) {
          System.out.println("List empty,can not perform delete operation");
          return null;
        }

        /* First save head value to return,then Make head to point next
         * node in the list
         * Again order is important 
         */

        int deletedNodeValue = head.getData();
        head = head.getNext();
        return deletedNodeValue;
    }

    @Override
    public Integer deleteLast() {

        //Check if list is already Empty 
 if(isEmpty()) {
  System.out.println("List is empty, return null, can not perform delete operation");  
  return null;
 }

 if(head.getNext() == null) {
  int deletedNode = head.getData() ;
  head = null;
  return deletedNode;
 }
 Node currentNode = head.getNext();
 Node prevNode = head;
 while(currentNode.getNext() != null) { 
  prevNode =currentNode;
  currentNode = currentNode.getNext();
 }
 int deletedNode = currentNode.getData(); 
 currentNode = null; 
 prevNode.setNext(null); 
 return deletedNode;
    }

    @Override
    public Integer delete(int loc) {

        /* validate given location to delete node,
         * we wont check with list size here
         * as it internally traverse complete list once
         */
        if (loc < 1) {

            System.out.println("Invalid Location specified to delete");
            return null;
        }

        Node currentNode = head;

        if (loc == 1) {
            return deleteFirst();
        }

        /* we will also check whether current node is not null
         * as location given can be can be more then list size
         */
        for (int i = 0; i < loc - 2 && currentNode != null; i++) {
            currentNode = currentNode.getNext();
        }

        if (currentNode == null) {
            System.out.println("Invalid Location specified to delete");
            return null;
        }

        int deletedNodeValue = currentNode.getData();
        currentNode.setNext(currentNode.getNext().getNext());
        
       return deletedNodeValue;

    }

    @Override
    public boolean deleteThis(int data) {

        if (head.getData() == data) {
            return (deleteFirst()!= null);
        }

        /* Check if list is already Empty
         * We are checking isEmpty after checking for head data as
         * deleteFirst also has list empty check
         * and we don't want to execute this check twice
         * by putting below isEmpty check at start of this method call
         */
        
        if (isEmpty()) {

          System.out.println("List empty,can not perform delete operation");
            return false;
        }
        Node currentNode = head;

        //Iterate list until node to delete is reached or list ends

        while (currentNode.getNext() != null) {

            if (currentNode.getNext().getData() == data) {

                currentNode.setNext(currentNode.getNext().getNext());
                return true;
            }
            currentNode = currentNode.getNext();
        }

        System.out.println("data not present in the list");
        return false;
    }

    /*
     * This method will return true if List is Empty else false.
     * List will be empty when head is null
     */

    @Override
    public boolean isEmpty() {
        return null == head;
    }

    @Override
    public void printList(Node head) {

        if (head == null) {
            System.out.println("Invalid node given");
            return;
        }

        Node currentNode = head;
        System.out.print("List is: [");

        while (currentNode != null) {
            System.out.print("    "+currentNode.getData());
            currentNode = currentNode.getNext();
        }
        System.out.println("    ]");
    }
 
     public void printList() {
 if (head == null) {

  System.out.println("Invalid node given");
  return;
 }
 Node currentNode = head;
 System.out.print("List is: [");
 while (currentNode != null) {
  System.out.print(" "+currentNode.getData());
  currentNode = currentNode.getNext();
 }
 System.out.println(" ]");
   }
 
      @Override
    public int getSize(Node head) {

        int count = 0;
        Node currentNode = head;

        while (currentNode != null) {

            count++;
            currentNode = currentNode.getNext();
        }
        return count;
    }

    public static void main(String[] args) {

        SLL myLst = new SLL();

        myLst.insert(new Node(41),0);
        myLst.insert(new Node(42),2);
        myLst.insert(new Node(43),1);
        myLst.insert(new Node(44),1);
        myLst.insert(new Node(45),2);
        myLst.insert(new Node(46),4);
        myLst.insert(null,3);
        
        myLst.insert(51,0);
        myLst.insert(52,2);
        myLst.insert(53,1);
        myLst.insert(54,1);
        myLst.insert(55,2);
        myLst.insert(56,4);

        myLst.insertAtStart(1);
        myLst.insertAtStart(2);
        myLst.insertAtStart(3);
        myLst.insertAtStart(4);

        myLst.insertAtStart(new Node(11));
        myLst.insertAtStart(new Node(12));
        myLst.insertAtStart(new Node(13));
        myLst.insertAtStart(new Node(14));

        myLst.insertAtStart(null);

        myLst.insertAtEnd(21);
        myLst.insertAtEnd(22);
        myLst.insertAtEnd(23);
        myLst.insertAtEnd(24);

        myLst.insertAtEnd(new Node(31));
        myLst.insertAtEnd(new Node(32));
        myLst.insertAtEnd(new Node(33));
        myLst.insertAtEnd(new Node(34));
        myLst.insertAtEnd(null);

        myLst.printList(myLst.head);
        System.out.println("=================deletefirst===============");

        myLst.deleteFirst();
        myLst.deleteFirst();
        myLst.deleteFirst();
        myLst.printList(myLst.head);

        System.out.println("=========delete from location==============");       

        myLst.delete(0);
        myLst.delete(1);
        myLst.delete(30);
        myLst.delete(2);

        myLst.printList(myLst.head);
        System.out.println("=========delete this(data)=================");

        myLst.deleteThis(31);
        myLst.deleteThis(131);
        myLst.deleteThis(45);

        myLst.printList(myLst.head);
    }
}
If we run the program we will get output like this:


Output
==========================================================================
Invalid Location specified to insert node
Invalid Location specified to insert node
Node you are trying to insert is null
Invalid Location specified to insert node
Node you are trying to insert is null
Node you are trying to insert is null
List is: [    14    13    12    11    4    3    2    1    54    55    53    56    44    52    45    43    46    21    22    23    24    31    32    33    34    ]
===========================deletefirst=============================
List is: [    11    4    3    2    1    54    55    53    56    44    52    45    43    46    21    22    23    24    31    32    33    34    ]
==========================delete from location========================
Invalid Location specified to delete node
Invalid Location specified to delete node
List is: [    4    2    1    54    55    53    56    44    52    45    43    46    21    22    23    24    31    32    33    34    ]
==========================delete this(data)==========================
data not present in the list
List is: [    4    2    1    54    55    53    56    44    52    43    46    21    22    23    24    32    33    34    ]

In next post we will talk about doubly Link List and Circular Link List and then some commonly asked question based on link list.

No comments :

Post a Comment