Monday, August 23, 2010

(Part 3) Singly Linked List with Generified Node element

This post is the continuation of "Singly Linked List with Generified Node element - Part 2".

Sometimes you wish to reverse a Linked List.
Reversing the Singly Linked List with constant extra space is a little tricky matter.
This is a question generally asked in technical interviews as well :D
Here is a function for it.
    public boolean reverse()
    {
        temp = head;
        int i;
        if(head.next!=null)
        {
            try
            {
                node<E> temp2=head.next;
                node<E> temp3=head.next.next;
                tail = head;
                tail.next = null;
                while(true)
                {
                    temp2.next = head;
                    head = temp2;
                    if(temp3 != null) {temp2 = temp3;}
                    else {break;};
                    if(temp3.next !=null)    {temp3 = temp3.next;}
                    else            {temp3 = null;};
                }
                head = temp2;
                return true;
            }
            catch(Exception e)
            {
                e.printStackTrace();
                return false;
            }
        }
        else
        {
            return true;
        }
    } 
Well, this function basically traverses the list viewing three nodes at a time and reverses the node.next member variable of the middle node. It reverses the list using O(1) extra space.



These were all public methods exposed to the user for use. Now comes some private methods.These are not seen by the user but are required for the internal working of the class.

getNode(E elem) method is required to fetch the node element(first node element if multiple such nodes exists) of the Linked List which has element 'elem' same as the 'elem' passed as arguement.
Note: 'same as' means that true is returned when you call object1.equals(object2). More on this in my next post.
    private node<E> getNode(E e)
    {
        temp = head;
        boolean flag = false;
        int i;
        for (i=0; i<size-1 ; i++)
        {
            if (temp.elem.equals(e))
            {
                flag = true;
                break;    
            } 
            temp = temp.next;
        }
        if(flag ==true)
         {
            return temp;
        }
        else
        {
            return null;
        }

    }


Sometimes for testing purpose, you need to print all the elements in the Linked List. I constructed a function for the same.
    public void printAll()
    {
        temp = head;
        int i;
        //System.out.println("Call to Printall function initiated");
        System.out.println();
        //System.out.println("The first element is "+head.elem);
        System.out.println("Size of the list is "+size);
        for (i=0; i<size ; i++)
        {
            try
            {
                System.out.println(temp.elem);
            }
            catch (NullPointerException e)
            {
                e.printStackTrace();
                System.out.println(i);
            }
            if (i!=size-1) temp = temp.next;
        }
    } 



Now lets talk about a function which rarely comes into use but we you need it, you really really need it !!
This function returns an array of E type with elements which are in the list after the specified element (passed as arguement).

    public E[] getRest(E e)
    {
        E[] temp_array=(E[])Array.newInstance(e.getClass(),remaining(e));
        temp = this.getNode(e);
        int i;   
        int array_index=0;
        do
        {
            try
            {
                temp_array[array_index] = temp.elem;
            }
            catch (NullPointerException ex)
            {
                ex.printStackTrace();
                //System.out.println(i);
            }
            array_index++;
            //if (temp.next!=null) temp = temp.next;
        }
        while ((temp = temp.next) != null);
        return temp_array;
    }  
Note: The element passed as arguement is also included in the returned array.
Note: For getRest(E e) function, you will need to import java.lang.reflect.Array in your code.
Note: This function generates a compiler warning as i am casting an object of 'Object' Class (newInstance returns an object of Object Class) into (E[]). This is also known as unchecked casts. It generates a compile time warning. But it is type safe so don't worry and go ahead.

In this function, I retrieved the Class Object associated with the elem e and then passed it along with the required size in the newInstance method of 'Array' class to create an array of the required type and size.
After that, I just traversed to the list assigning the required elements to the newly created array.


That is it.
You are done.
For the complete code, go here.
Do post your comments about the post.

(Part 2) Singly Linked List with Generified Node element

This is the continuation of the post " Singly Linked List with Generified Node element - Part 1".

Sometimes we want to add an element at some specific index. For that, we need another function.
    public E addElem(E e,int index)
    {

        if(index ==0)
        {
            node<E> newNode = new node<E>();
            newNode.elem = e;
            newNode.next = head;
            head = newNode;
            this.size++;
        }
        else
        {
            temp = head;
            for (int i=0; i<index-1 ; i++)
            {
                 temp = temp.next;
            }
            node<E> newNode = new node<E>();
            newNode.next = temp.next;
            newNode.elem = e;
            temp.next = newNode;
            this.size++;
        }
        return e;
    } 
This function constructs a new node with the provided element, inserts it between the Linked List at the specified index by playing a little bit with the member variables of the adjoining nodes.
Again, we need to consider two cases:
  1. The provided index is 0, i.e. the user wants to insert the new element at the begining of the list. In such a case, we need to modify the head variable.
  2. The provided index is between 0(exclusive) and size-1(inclusive). In such a case, we construct a new node, change the 'next' variable of (index-1)th node to this new node, initialize 'next' of this new node to the (index+1)th node.


After storing your elements in the list, you do need to retrieve them and use them. So we do need a function which fetches the data from the Linked List.

    public E getElem(int index)
    {
            temp = head;
            for (int i=0; i<index ; i++)
            {
                 temp = temp.next;
            }
            return temp.elem;
    }
This function will traverse the list to reach the specified index, retrieve the node and return the element stored at it.


Sometimes you will need to know where in the list, a particular element is situated. You need a indexOf() function  for this.
    public int indexOf(E e)
    {
        temp = head;
        boolean flag = false;
        int i;
        for (i=0; i<size-1 ; i++)
        {
            if (temp.elem.equals(e))
            {
                flag = true;
                break;    
            } 
            temp = temp.next;
        }
        if(flag ==true)
        {
            return i;
        }
        else
        {
            return -1;
        }

    }
This function will traverse the list to find a node with 'elem' 'same as' the specified 'e' (passed as arguement).


Sometimes you need to know how many elements are remaining in the list after a particular element. You can construct a function for this as well :)
public int remaining(E e)
 {
  int tempindex = this.indexOf(e);
  int remainingnum = size - tempindex;
  return remainingnum;
 } 
Note: The node with 'elem' = e, is also counted.


It might happen that you want to remove a particular element in the Linked List and save some processing time when you are going through the list again and again. For this you need to make a remove function. Remove function comes in two flavours:
  1. remove(E elem)
  2. remove(int index)
remove(E elem) method removes a particular node whose element 'elem' is 'same as'  the 'elem' passed as arguement.
Note: 'same as' means that true is returned when you call object1.equals(object2). More on this in my next post.

    public E remove(E e)
    {
        temp = head;
        int i;
        E e_temp;
        boolean flag= false;
        node<E> temp2=head;

        for (i=0; i<size; i++)
        {
            if(temp.elem.equals(e))
            {
                flag = true;
                break;
            }
            temp2 = temp;
            temp = temp.next;
        }
        if (flag == true)
        {
            if (i ==0)
            {
                e_temp = head.elem;
                head = head.next;
                this.size--;
                return e_temp;
            }
            else if (i == size-1)
            {
                e_temp= tail.elem;
                tail = temp2;
                tail.next = null;
                this.size--;
                return e_temp;
            }
            else
            {
                temp2.next = temp.next;
                this.size--;
                return temp.elem;
            }
        }
        else
        {
            return null;
        }

    }
This function traverses the list to find the first occurence of the element 'e' and then takes change the pointers of the adjoining nodes to remove the node from the list. We have to take into account three cases.
  1. The node to be removed is the head node.
  2. The node to be removed is the tail node.
  3. The node to be removed is any other node in between.

remove(int index) removes the element at index='index' (passed as arguement) in the function.
Note: Index starts from 0.
    public E remove(int index)
    {
        temp = head;
        int i;
        E e_temp;
        
        if(index == 0)
        {
            e_temp = head.elem;
            head = head.next;
        }
        else if(index == size-1)
        {
            e_temp = tail.elem;
            for (i=0; i<size-2; i++)
            {
                temp = temp.next;
            }
            tail = temp;
            tail.next = null;
        }
        else
        {
            for (i=0; i<index-1; i++)
            {
                temp = temp.next;
            }
            e_temp = temp.next.elem;
            temp.next = temp.next.next;
        }
        this.size--;
        return e_temp;
    } 
This function traverses the list to get to the specified index and then changes the pointers of the adjoining nodes to remove the node from the list. Again we have to take into account three cases.
  1. The node to be removed is the head node.
  2. The node to be removed is the tail node.
  3. The node to be removed is any other node in between.
Go to the next post "Singly Linked List with Generified Node element - Part 3" for more function.

    (Part 1) Singly Linked List with Generified Node element - Part 1

    Well,
    I thought of practising some Data Structures with Java.
    The first structure that came to my mind was a Linked List.
    So, I started writing a Singly Linked List (Single Generified element for the nodes).

    For those who are new to generics in java, wait for my next post. I will be explaining generics in the next post.

    Here we go ...
    Well,
    First of all you need a Node Class.
    class node<E>
    {
        E elem;
        node<E> next;
    }
    
    Here is your node class which has a generic type parameter E.
    It holds two things:
    1. 'elem' variable of E type
    2. 'next' variable of node<E> type (which holds the reference to the next node).

    Next, you need a Linked List class (named ll in this article) which will wrap everything.
    Basically, each object of Linked List Class contains some basic reference variables which are initialized and changed by the member functions.

    class ll<E>
    {
        node <E> head;
        node <E> tail;
        node <E> temp;
        private int size=0;
    } 
    These are the basic member variables needed for all the funtionalities of the class.
    1. node <E> head refers to the head of the Linked List i.e. the first element of the Linked List.
    2. node <E> tail refers to the tails of the Linked List i.e. the last element of the Linked List.
    3. node <E> temp is used in various member functions for temporary storage.
    4. int size is used to store the size of the Linked List. It increases and decreases dynamically as elements are added and removed from the Linked List.


    Now lets come to the main part of a class i.e. functions.
    add(E Elem) method:
    public E addElem(E e)
        {
            if(head==null)
            {
                head = new node<E>();
                head.elem = e;
                head.next = null;
                tail=head;
            }
            else
            {
                tail.next = new node<E>();
                tail = tail.next;
                tail.elem = e;
            }
            this.size++;
            return e;            
        } 
    This method is used to add element at the end of the Linked List. In this method we need to consider two cases:
    1. Case 1: The list is empty. In such a case, we need to create a new node with the provided element and assign it to head variable. Remember to assign the same node to tail as well. You can do this by "tail = head".
    2. Case 2: The list is not empty and contains at least one element. In such a case, all you need to do is contruct a new node with the provided 'elem', assign it to tail.next and assign the new node to tail.

    Go to the next post for More functions.

    Sunday, August 22, 2010

    Welcome !!

    Welcome to my blog !

    As the name of the blog suggests, my blog will be basically technical.
    I have this love for Data Structures and new algorithms.
    I love to solve coding problems and hence www.codechef.com is one of my favourite websites.

    I will be soon posting my first (second :P) post about Linked Lists.


    Happy Reading.

    Oh btw,
    Here are my profiles just in case you are interested:
    LinkedIn : http://in.linkedin.com/in/prateekguptabits
    Facebook : http://www.facebook.com/prateek.g
    Google Profile : http://www.google.com/profiles/mailtoprateek
    Twitter : http://twitter.com/prateek_g