ADT: LINKED LIST

TOPICS


·  ADT: Linked List:  Definition, Operations, Examples

·  The class LinkedListClass

·  ADT Unordered List (Linked List Implementation)

·  ADT Ordered List (Linked List Implementation)

OUTLINE



ADT Linked List
 

·  When we discussed the ADTs unsorted and sorted lists, we looked at  implementations using arrays. All the implementations discussed used a built-in array stored in contiguous memory locations, implementing operations to insert and delete by moving list items around in the array, as needed (shift left or shift right). In general, array implementations of ADTs are not the most efficient solutions when there is a high number of insertions and deletions.

·  Array limitations:

·  The solution would be a dynamic data structure to ensure  that the collection could shrink or grow during program execution as needed (no size limitations)  and  the data items don't need to be stored contiguously in memory.  A linked list is such a dynamic data structure = better alternative to the built-in array implementation.

·  The principal benefit of a linked list over a conventional array is that the order of the linked items may be different from the order that the data items are stored in memory or on disk. For that reason, linked lists allow insertion and removal of nodes at any point in the list. On the other hand, linked lists by themselves do not allow random access to the data, or any form of efficient indexing. Thus, many basic operations (such as obtaining the last node of the list, or finding a node that contains a given data, or locating the place where a new node should be inserted) may require going over most of the list elements (link list traversal).

·  Definition: Linked list = a collection of nodes, each containing at least one member that gives the location of the next node in the list. In the simplest case, each node has 2 members: a data member (the data value of the list item) and a link member (a value locating the successor of this node). The fact that the link member is present allows us to place individual nodes anywhere in memory, not only in contiguous memory locations (as with arrays).

·  List nodes can be "linked" into chains to store a list of values. Each list node object stores:

·  one piece of (some type) data

·  a reference to another list node

·  NOTES:

·  Definition: Linked list traversal = stepping through the nodes of a linked list. Basic operations of a linked list that require the link to be traversed; search, insert, delete.

·  NOTE: You should not traverse a linked list using head (the list will be destroyed). Instead, use another reference variable of the same type as head.

·  Linked list traversal (Java code):

Node current = head;
while (current != null){
    //Do something - process current
    current = current.link;
}

·  Example of linked list traversal: display the data /in each node:

Node current = head;
while (current != null){
    System.out.println(current.info + " ");
    current = current.link;
}

·  Definition: Iterator = An object that allows a client to traverse the elements of a collection, regardless of its implementation. An iterator as an object that produces each element of a collection one element at a time.

·  Benefit: A common way to examine any collection's elements.

·  An iterator remembers a position within a collection, and allows you to:

·  Some common iterator methods:

hasNext():  returns true if there are more elements in the collection
next():  returns the next element from the collection (throws a NoSuchElementException if there are none left to examine) - gives access to the next element in the list
remove():  removes from the collection the last value returned by next() (throws IllegalStateException if you have not called next() yet)

·  Check these notes for some linked list examples.



The class LinkedListClass
 

·  The class LinkedListClass  implements the LinkedListADT interface. This is an abstract class.

·  Reminder: Abstract class = a hybrid between an interface and a class. An abstract class defines a superclass type that can contain method declarations (like an interface) and/or method bodies (like a class).

·  Like interfaces, abstract classes cannot be instantiated (cannot use new to create any objects of their type).

·  What goes in an abstract class?

·  Structure of a linked list node:

·  Definition: Nested class = A class defined inside of another class. A nested class can be created as static (static nested classes) or non-static (inner classes). Usefulness:

·  Inner classes ensure increased encapsulation. They are hidden from other classes (encapsulated); inner objects can access/modify the fields of the outer object.

·  Inner classes ensure the grouping of classes that are only used in one place.

·  Inner classes can lead to more readable and maintainable code.

·  If an outer class declares a type parameter, inner classes can also use that type parameter. The inner class should NOT redeclare the type parameter.  (If it does, it will create a second type parameter with the same name.)

·  The classes LinkedListNode and LinkedListIterator are inner classes inside the LinkedListClass class.

·  Definition of the LinkedListClass class:

public abstract class LinkedListClass<T> implements LinkedListADT<T> {
      //Place the definition of the inner class LinkedListNode<T> here.
      //Place the definition of the inner class LinkedListIterator<T> here.
      //Place the definition of the LinkedListClass instance variables here
      //Place the definition of the nonabstract methods here
      //Place the definition of the abstract methods here.
}

·  LinkedListNode class:

   public T info;
   public LinkedListNode<T> link;
   public LinkedListNode();
   public LinkedListNode(T elem, LinkedListNode<T> ptr);
   public Object clone();
   public String toString();

 

·  Instance variables for LinkedListClass:

    protected LinkedListNode<T> first;//variable to store the address of the first  node of the list
  protected LinkedListNode<T> last; //variable to store the address of the last node of the list
  protected int count;            //variable to store the number of nodes in the list

 

·  Nonabstract methods:

  public LinkedListClass();
  public boolean isEmptyList();
  public void initializeList();
  public void print();
  public int length();
  public T front
  public T back();
  public Object clone();
 

·  Abstract methods (to be implemented in the UnorderedLinkedList and OrderedLinkedList classes):

  public abstract boolean search(T searchItem);
  public abstract void insertFirst(T newItem);
  public abstract void insertLast(T newItem);
  public abstract void deleteNode(T deleteItem);

 

·  The LinkedListClass has two derived classes: UnorderedLinkedList and OrderedLinkedList

·  The (Java) implemetation:
//Interface: LinkedListADT extends
//Class: Cloneable
public interface LinkedListADT<T> extends Cloneable {
    public boolean isEmptyList();        //Method to determine whether the list is empty.
    public void initializeList();        //Method to initialize the list to an empty state.
    public void print();                 //Method to output the data contained in each node.
    public Object clone();               //Returns a copy of objects data in store (shallow copy)
    public int length();                 //Method to return the number of nodes in the list.
    public T front();                    //Method to return a reference to the first node
    public T back();                     //Method to return a reference to the last node
    public boolean search(T searchItem); //Method to determine whether searchItem is in the list.
    public void insertFirst(T newItem);  //Method to insert newItem as the first item in the list.
    public void insertLast(T newItem);   //Method to insert newItem at the end of the list.
    public void deleteNode(T deleteItem);//Method to delete deleteItem from the list.
}

//Class: LinkedListClass implements
//Interface: LinkedListADT
import java.util.*;
public abstract class LinkedListClass<T> implements LinkedListADT<T> {
    protected class LinkedListNode<T> implements Cloneable {
        public T info;
        public LinkedListNode<T> link;
        //Default constructor
        public LinkedListNode() {
            info = null;
            link = null;
        }

        //Alternate constructor
        public LinkedListNode(T elem, LinkedListNode<T> ptr) {
            info = elem;
            link = ptr;
        }

        public Object clone() {
            LinkedListNode<T> copy = null;
            try {
                copy = (LinkedListNode<T>) super.clone();
            }
            catch (CloneNotSupportedException e) {
                return null;
            }
            return copy;
        }

        public String toString() {
            return info.toString();
        }
    } //end class LinkedListNode

    //Instance variables of the class LinkedListClass
    protected LinkedListNode<T> first;//address of the first node/list
    protected LinkedListNode<T> last; //address of the last node/list
    protected int count;            //number of nodes in the list

    //Default constructor
    public LinkedListClass() {
        first = null;
        last = null;
        count = 0;
    }

    public boolean isEmptyList() {
        return (first == null);
    }

    public void initializeList() {
        first = null;
        last = null;
        count = 0;
    }

    public void print()  {
        LinkedListNode<T> current; //variable to traverse the list
        current = first;
        while (current != null) {//while more data to print
            System.out.print(current.info + " ");
            current = current.link;
        }
    }

    public int length() {
        return count;
    }

    public T front()   {
        return first.info;
    }

    public T back()  {
        return last.info;
    }

    public Object clone() {
        LinkedListClass<T> copy = null;
        try  {
            copy = (LinkedListClass<T>) super.clone();
        }
        catch (CloneNotSupportedException e){
            return null;
        }

        //If the list is not empty clone each node of the list.
        if (first != null) {
            //Clone the first node
            copy.first = (LinkedListNode<T>) first.clone();
            copy.last = copy.first;
            LinkedListNode<T> current;
            if (first != null)
                current = first.link;
            else
                current = null;
            //Clone the remaining nodes of the list
            while (current != null) {
                copy.last.link = (LinkedListNode<T>) current.clone();
                copy.last = copy.last.link;
                current = current.link;
            }
        }
        return copy;
    }

    //abstract methods

    public abstract boolean search(T searchItem);
    public abstract void insertFirst(T newItem);
    public abstract void insertLast(T newItem);
    public abstract void deleteNode(T deleteItem);
}



The class UnorderedLinkedList
 

·  The implemenation of a UnorderedLinkedList class extends the abstract class LinkedListClass (which implements the LinkedListADT interface previously discussed) --> we need to implement a constructor, and the abstract methods:
   
public abstract boolean search(T searchItem);
  public abstract void insertFirst(T newItem);
  public abstract void insertLast(T newItem);
  public abstract void deleteNode(T deleteItem);

• Method search: In the array-based implementation for the unordered list we used the linear search algorithm – similar approach with the linked list implementation.
• Methods insertFirst and insertLast insert a new node holding the item at the beginning and at the end of the linked list. Since the list is unordered, the item to be inserted can be inserted wherever we choose, and we choose the easiest locations: at the front or at the end.
• Method deleteNode: To delete an item in a unordered linked list:

·  The (Java) implemetation:
//Class: UnorderedLinkedList extends
//Class: LinkedListClass
public class UnorderedLinkedList<T> extends LinkedListClass<T> {
    //Default constructor
    public UnorderedLinkedList() {
        super();
    }

    public boolean search(T searchItem)  {
        LinkedListNode<T> current; //variable to traverse the list
        current = first;
        while (current != null)
            if (current.info.equals(searchItem))
                return true;
            else
               current = current.link;
        return false;
    }

    public void insertFirst(T newItem) {
        LinkedListNode<T> newNode//variable to create the new node
        //create and insert newNode before first
        newNode = new LinkedListNode<T>(newItem, first);
        first = newNode;
        if (last == null)
            last = newNode;
        count++;
    }

    public void insertLast(T newItem)  {
        LinkedListNode newNode; //variable to create the new node
        //create newNode
        newNode = new LinkedListNode(newItem, null);
        if (first == null) {
            first = newNode;
            last = newNode;
        }
        else {
            last.link = newNode;
            last = newNode;

        }
        count++;
    }

    public void deleteNode(T deleteItem) {
        LinkedListNode<T> current; //variable to traverse the list
        LinkedListNode<T> trailCurrent; //variable just before current
        boolean found;
        //Case 1; the list is empty
        if ( first == null)
            System.err.println("Cannot delete from an empty list.");
        else {
            //Case 2: the node to be deleted is first
            if (first.info.equals(deleteItem)) {
                first = first.link;
                if (first == null)  //the list had only one node
                    last = null;
                count--;
            }
            else {  //search the list for the given info
                found = false;
                trailCurrent = first; //trailCurrent points to first node
                current = first.link; //current points to second node
                while (current != null && !found) {
                    if (current.info.equals(deleteItem))
                        found = true;
                    else {
                        trailCurrent = current;
                        current = current.link;
                    }
                }
                //Case 3; if found, delete the node
                if (found) {
                    count--;
                    trailCurrent.link = current.link;
                    if (last == current)  //node to be deleted was the last node
                       last = trailCurrent;
                }
                else
                   System.out.println("Item to be deleted is not in the list.");
            }
        }
    }
}

//Class: ClientUnorderedLinkedListInt
import java.util.*;

public class ClientUnorderedLinkedListInt {

    static Scanner input = new Scanner(System.in);

    public static void main(String[] args) {

        UnorderedLinkedList<Integer> intList = new UnorderedLinkedList<Integer>();

        UnorderedLinkedList tempList;

        Integer num;

        System.out.println("Enter integers (999 to stop)");

        num = input.nextInt();

        while (!num.equals(999)) {

            intList.insertLast((Integer) num);

            num = input.nextInt(); //getInt()?

         }

        System.out.println("\nTesting .insertLast. The original list is: ");

        intList.print();

        System.out.println("\nTesting .length. The length of the original list is: " + intList.length());

        if (!intList.isEmptyList()) {

            System.out.println("Testing .front. First element/original list: " + intList.front());

            System.out.println("Testing .back. Last element/original list: "  + intList.back());

        }

        tempList = (UnorderedLinkedList<Integer>) intList.clone();

        System.out.println("Testing .clone. The copy list is: ");

        tempList.print();

        System.out.println("\nTesting .length. The length of the copy list is: " + tempList.length());

        System.out.print("Testing .search. Enter the number to search for/original list: ");

        num = input.nextInt();//getInt()?

        if (intList.search(num))

            System.out.println(num + " found in original list.");

        else

            System.out.println(num + " is not in original list.");

        System.out.print("Testing .remove. Enter the number to be deleted from original list: ");

        num = input.nextInt(); //getInt()?

        intList.deleteNode(num);

        System.out.print("After deleting " + num + " the original list is: ");

        intList.print();

        System.out.println("\nAfter delete, the length of the original list is: " + intList.length());

        System.out.println("The original list is: ");

        intList.print();

        System.out.println("\nThe length of the original list is: " + intList.length());

        System.out.println("The copy list is: ");

        tempList.print();

        System.out.println("\nThe length of the copy list is: " + tempList.length());

    }

}

OUTPUT:
Enter integers (999 to stop)

 1 2 3 4 5 6 7 8 9 11 44 22 555 33 66 999

 

Testing .insertLast. The original list is: 

1 2 3 4 5 6 7 8 9 11 44 22 555 33 66

Testing .length. The length of the original list is: 15

Testing .front. First element/original list: 1

Testing .back. Last element/original list: 66

Testing .clone. The copy list is: 

1 2 3 4 5 6 7 8 9 11 44 22 555 33 66

Testing .length. The length of the copy list is: 15

Testing .search. Enter the number to search for/original list: 333

333 is not in original list.

Testing .remove. Enter the number to be deleted from original list: 22

After deleting 22 the original list is: 1 2 3 4 5 6 7 8 9 11 44 555 33 66

After delete, the length of the original list is: 14

The original list is: 

1 2 3 4 5 6 7 8 9 11 44 555 33 66

The length of the original list is: 14

The copy list is: 

1 2 3 4 5 6 7 8 9 11 44 22 555 33 66

The length of the copy list is: 15  



The class OrderedLinkedList
 

·  The implemenation of an OrderedLinkedList class extends the abstract class LinkedListClass. The LinkedListClass and the LinkedListADT interface are the same as those used in the implementation for the UnorderedLinkedListà We need to implement a constructor, add a method to insert in place and add the abstract methods:
       
public abstract boolean search(T searchItem);
    public abstract void insertFirst(T newItem);
    public abstract void insertLast(T newItem);
    public abstract void deleteNode(T deleteItem);
 

·  Method search: In the array-based implementation for the ordered list we used the binary search algorithm - cannot be used with a linked list (Why? Because you cannot get directly to the middle of the list, if no index available.) To search the list for a particular item we must follow the links down the list one by one, just like in the unordered linked list. However, this approach can be improved à if the item is not in the list, we can stop searching when the value in the node we are currently examining is larger than the item we are searching for (Why? Because the list is sorted, we know that the rest of the values are larger still, and cannot possibly match the search item)

·  Method insert: Inserting in an ordered linked list is more complicated than what we have done so far because we have to handle more special cases. Note: In the array-based implementation for the ordered list we found first the location for the new item; next, we had to shift right all the elements to make room for the new item. With the linked list approach we don’t have to shift any elements. To insert an item in an ordered linked list

·   Methods insertFirst and insertLast don’t make much sense for the ordered list à they just make calls to insert to insert in place (to keep the list ordered)

·  Method deleteNode: To delete an item in an ordered linked list:

·  The (Java) implemetation:
//Class: OrderedLinkedList extends
//Class: LinkedListClass
public class OrderedLinkedList<T> extends LinkedListClass<T> {
    //Default constructor
    public OrderedLinkedList()    {
        super();
    }

    public boolean search(T searchItem)  {
        LinkedListNode<T> current; //variable to traverse the list
        boolean found;
        current = first;  //set current to point to the first node in the list
        found = false;
        while (current != null && !found )  {
            Comparable<T> temp = (Comparable<T>) current.info;
            if (temp.compareTo(searchItem) >= 0)
                found = true;
            else
                current = current.link; //make current point to the next node
        }
        if (found)
           found = current.info.equals(searchItem);
        return found;
    }

    public void insert(T insertItem)  {
        LinkedListNode<T> current;  //variable to traverse the list
        LinkedListNode<T> trailCurrent; //variable just before current
        LinkedListNode<T> newNode//variable to create a node
        boolean  found;
        newNode = new LinkedListNode<T>(insertItem, null); //create the node
        //Case 1; the list is empty
        if (first == null) {
           first = newNode;
           last = newNode;
           count++;
        }
        else {
            trailCurrent = first;
            current = first;
            found = false;
            while (current != null && !found) {//search the list
                Comparable<T> temp = (Comparable<T>) current.info;
                if (temp.compareTo(insertItem) >= 0)
                   found = true;
                else {
                   trailCurrent = current;
                   current = current.link;
                }
            }
            //Case 2
            if (current == first) {
                newNode.link = first;
                first = newNode;
                count++;
            }
            //Case 3
            else {
                trailCurrent.link = newNode;
                newNode.link = current;
                if (current == null)
                    last = newNode;
                count++;
            }
        }
    }

    public void insertFirst(T newItem) {
        //the list is sorted - will call insert!
        insert(newItem);
    }

    public void insertLast(T newItem) {
        //the list is sorted - will call insert!
        insert(newItem);
    }

    public void deleteNode(T deleteItem) {
        LinkedListNode<T> current;      //variable to traverse the list
        LinkedListNode<T> trailCurrent; //variable just before current
        boolean found;
        //list is empty.
        if (first == null)
            System.err.println("Cannot delete from an empty list.");
        else {
            if (first.info.equals(deleteItem)) {
                first = first.link;
                if (first == null)
                    last = null;
                count--;
            }
            else { //search the list for the node with the given info
                found = false;
                trailCurrent = first; //trailCurrent points to the first node
                current = first.link; //current points to the second node
                while (current != null && !found) {
                    Comparable<T> temp = (Comparable<T>) current.info;
                    if (temp.compareTo(deleteItem) >= 0)
                        found = true;
                    else {
                        trailCurrent = current;
                        current = current.link;
                    }
                }
                if (current == null)
                    System.out.println("Item to be deleted is not in the list.");
                else
                    if (current.info.equals(deleteItem)) { //item to be deleted is in the list
                         if (first == current) {
                            first = first.link;
                            if (first == null)
                                last = null;
                            count--;
                        }
                        else {
                            trailCurrent.link = current.link;
                            if (current == last)
                                last = trailCurrent;
                            count--;
                        }
                    }
                    else
                        System.out.println("Item to be deleted is not in the list.");
            }
        }
    }
}

//Class: ClientOrderedLinkedListInt

import java.util.*;

public class ClientOrderedLinkedListInt {

    static Scanner input = new Scanner(System.in);

    public static void main(String[] args) {

        OrderedLinkedList<Integer> intList = new OrderedLinkedList<Integer>();

        OrderedLinkedList tempList;

        Integer num;

        System.out.println("Enter integers (999 to stop)");

        num = input.nextInt();

        while (!num.equals(999)) {

            intList.insert((Integer) num);

            num = input.nextInt();//getInt()?

        }

        System.out.println("\nTesting .insert. The original list is: ");

        intList.print();

        System.out.println("\nThe length of the original list is: " + intList.length());

        if (!intList.isEmptyList()) {

            System.out.println("\nTesting .front. First element/original list: " + intList.front());

            System.out.println("Testing .back. Last element/original list: "  + intList.back());

        }

        tempList = (OrderedLinkedList<Integer>) intList.clone();

        System.out.println("Testing .clone. The copy list is: ");

        tempList.print();

        System.out.println("\nThe length of the copy list is: " + tempList.length());

        System.out.print("Testing .search. Enter the number to search for/original list: ");

        num = input.nextInt();//getInt()?

        if (intList.search(num))

            System.out.println(num + " found in original list.");

        else

            System.out.println(num + " is not in original list.");

        System.out.println("Testing shallow copy/deep copy. Delete from original list. What about the clone? ");

        System.out.print("Enter the number to be deleted from original list: ");

        num = input.nextInt();//getInt()?

        intList.deleteNode(num);

        System.out.println("\nAfter deleting " + num + " the original list is: ");

        intList.print();

        System.out.println("\nThe new length of the original list is: " + intList.length());

        System.out.println("The copy list is: ");

        tempList.print();

        System.out.println("\nThe length of the copy list is: " + tempList.length());

    }

}

OUTPUT:


Enter integers (999 to stop)

9 8 7 6 5 4 3 2 1 99 88 44 55 11 33 77 66 999

 

Testing .insert. The original list is: 

1 2 3 4 5 6 7 8 9 11 33 44 55 66 77 88 99

The length of the original list is: 17

 

Testing .front. First element/original list: 1

Testing .back. Last element/original list: 99

Testing .clone. The copy list is: 

1 2 3 4 5 6 7 8 9 11 33 44 55 66 77 88 99

The length of the copy list is: 17

Testing .search. Enter the number to search for/original list: 55

55 found in original list.

Testing shallow copy/deep copy. Delete from original list. What about the clone?

Enter the number to be deleted from original list: 44

 

After deleting 44 the original list is: 

1 2 3 4 5 6 7 8 9 11 33 55 66 77 88 99

The new length of the original list is: 16

The copy list is: 

1 2 3 4 5 6 7 8 9 11 33 44 55 66 77 88 99

The length of the copy list is: 17


Key Terms:
Abstract class: A hybrid between an interface and a class, created with the
abstract reserved word.
Circular linked list: A linked list in which the last node points to the first node.
Doubly linked list: A linked list in which every node has a next pointer and a back pointer.
Head (first): A reference variable that stores the address of the first node in a list.
Inner class: A non-static nested class.
Link: The component of a node that stores the address of the next node in a list.
Linked list: A collection of components, called nodes.
Nested class: A class defined within a class.
Node: A data structure that has two components: info and link.


Additional Resources:
1. (Oracle) The Java Tutorials, Nested classes: : http://java.sun.com/docs/books/tutorial/java/IandI/abstract.html
2. (Oracle) The Java Tutorials, Abstract methods and classes: http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html
3. Linked List:
http://en.wikipedia.org/wiki/Linked_list

4. Iterators: http://en.wikipedia.org/wiki/Iterators


References:
[1] Java Programming: From Problem Analysis to Program Design, by D.S. Malik, Thomson Course Technology, 2008
[2] Building Java Programs: A Back to Basics Approach, by Stuart Reges, and Marty Stepp, Addison Wesley, 2008.