Linked-List Implementation of Stacks

One disadvantage of using an array to implement a stack is the wasted space---most of the time most of the array is unused. A more elegant and economical implementation of a stack uses a linked list, which is a data structure that links together individual data objects as if they were ``links'' in a ``chain'' of data.

Here is a sketch of a linked-list-based ``stack'' that holds 1, then 5, and then 20 at the bottom:

          ---
top ---> | 1 |
         |---|      ---
         | o-|---> | 5 |
          ---      |---|      ----
                   | o-|---> | 20 |
                    ---      |----|
                             |null|
                              ----
The list consists of three ``cells,'' each of which holds a data object and a ``link'' to another cell. A variable, top, holds the address of the first cell in the list. An empty stack looks like this:
top ---> null
(That is, variable top holds value, null.) Each time an object is pushed, a cell is constructed, the object is inserted into the cell, and the cell is linked to the front of the chain of cells. For example, pushing 20 onto the empty stack gives us
          ----
top ---> | 20 |
	 |--- | 
	 |null|
          ----
After 5 and then 1 are pushed, we obtain the picture first seen.

Say that we pop an object from the stack; the picture changes to this:

                    ---
          top ---> | 5 |
	           |---|      ----
                   | o-|---> | 20 |
                    ---      |----|
	                     |null|
                              ----

How to code Cells and Stacks

Figure 7 defines class Cell, which one uses to create the cells in the list.

FIGURE 7: list cell======================================================

/** Cell models a cell of a linked list.  */
public class Cell
{ private Object val;  // value in the cell
  private Cell next;   // the address of the next cell in the list

  /** Constructor Cell builds a new cell 
    * @param value - the value inserted in the cell
    * @param link - the cell that is chained to this new cell */
  public Cell(Object value, Cell link)
  { val = value; 
    next = link;
  }

  /** getVal  returns the value held in the cell  */
  public Object getVal()
  { return val; }

  /** getNext  returns the address of the cell chained to this one */
  public Cell getNext()
  { return next; }

  /** setNext  resets the address of the cell chained to this one
    * @param link - the address of the Cell that is chained to this one */
  public void setNext(Cell link)
  { next = link; }
}

ENDFIGURE================================================================
class Cell is really just a container to hold the object, val, and the linkage, next.

The three-celled linked list sketched above can be manually constructed by this sequence of initializations:

Cell cell1 = new Cell(new Integer(20), null);
Cell cell2 = new Cell(new Integer(5), cell1);
Cell top = new Cell(new Integer(1), cell2);
Since class Cell holds values of type Object, we must ``wrap'' the integers into Integer objects before placing them in cells.

The example list looks like a stack, and indeed, it is easy to revise the coding of class Stack so that it is implemented with a linked list. Figure 8 shows the new implementation of a stack.

FIGURE 8: stack implemented by a linked list============================

/** Stack implements a stack as a linked list */
public class Stack
{ private Cell top;  // marks the topmost Cell of the stack

  /** Constructor Stack creates an empty stack */
  public Stack()
  { top = null; }

  /** push  inserts a new element onto the stack
    * @param ob - the element to be added */
  public void push(Object ob)
  { top = new Cell(ob, top); }

 /** pop  removes the most recently added element
    * @return the element removed from the stack
    * @exception RuntimeException if stack is empty */
  public Object pop()
  { if ( top == null )
       { throw new RuntimeException("Stack error: stack empty"); }
    Object answer = top.getVal(); 
    top = top.getNext(); 
    return answer; 
  }

 /** top  returns the identity of the most recently added element
    * @return the element
    * @exception RuntimeException if stack is empty */
  public Object top()
  { if ( top == null )
       { throw new RuntimeException("Stack error: stack empty"); }
    return top.getVal();
  }

  /** isEmpty  states whether the stack has 0 elements.
    * @return whether the stack has no elements  */
  public boolean isEmpty()
  { return (top == null); }
}

ENDFIGURE==============================================================

Here is an important point: In terms of the perspective of the user of the stack, the coding in Figure 7 looks the same and computes the same behaviors as the earlier version of class Stack --- we have changed the internal implementation of class Stack but maintained the same behavior. (In this sense, the coding in Figure 7 is an equivalement replacement part for any program that requires a stack.)

The linked list implementation has a simpler internal state and simpler codings of its methods than the stack whose implementation is based on an array. Here is a picture of the storage configuration when a stack named operands was used to push 20 then 5 then 1:

                  ----
Stack operands ==| a1 |
                  ----
 a1 : Stack
 -------------------
 | Cell top ==| a15 |
 |             ----- 
 |  ...

  a11 : Cell                a13 : Cell                a15: Cell
 ------------              ------------               ------------
 | Object val ==| a10 |    | Object val ==| a12 |    | Object val ==| a14 |
 |               -----     |               -----     |               -----
 | Cell next ==| null |    | Cell next ==| a11 |     | Cell next ==| a13 | 
 |              ------     |              -----      |              -----
 |  ...                    |  ...                    | ...

  a10 : Integer         a12 : Integer           a14 : Integer
 ---------------      --------------        --------------
 | (holds 20)         | (holds 5)           | (holds 1)
Say that operands.pop() is used twice, removing two values from the stack, and operands.push(new Integer(4)) is used next. The storage configuration changes to this:
                  ----
Stack operands ==| a1 |
                  ----
 a1 : Stack
 -------------------
 | Cell top ==| a17 |
 |             ----- 
 |  ...

  a11 : Cell                a13 : Cell                a15: Cell
 ------------              ------------               ------------
 | Object val ==| a10 |    | Object val ==| a12 |    | Object val ==| a14 |
 |               -----     |               -----     |               -----
 | Cell next ==| null |    | Cell next ==| a11 |     | Cell next ==| a13 |
 |              ------     |              -----      |              -----
 |  ...                    |  ...                    | ...

  a17 : Cell                         a16 : Integer
 ------------                       ---------------
 | Object val ==| a16 |             | (holds 4)
 |               ----- 
 | Cell next ==| a11 |
 |              ------
 |  ...

  a10 : Integer         a12 : Integer           a14 : Integer
 ---------------      --------------        --------------
 | (holds 20)         | (holds 5)           | (holds 1)
The cells at addresses a13 and a15 are no longer used by the stack. What happens to them? Do they remain in computer storage, unused, forever? The answer is ``no''--- Embedded within the Java Virtual Machine is an extra program, called a garbage collector, that periodically examines computer storage and destroys all objects that are not used by the executing Java program.

(BeginFootnote: An object, ob, is ``used'' in the sense that, starting from an application's main method, we can find an address of an object, and that object holds an address of another object, and so on, until an object is reached that holds the address of ob. EndFootnote)

Thanks to the garbage collector program, we need not make special efforts to destroy the cell that is unneeded after an invocation of pop; the cell will disappear automatically. Also, the garbage collection will dispose of those Integer objects that are no longer used by the application.

The importance of the garbage collector to programming style cannot be overstated---it lets a programmer use objects as freely as numbers, creating them at will, using them with methods as arguments and results, and not worrying about their fate when they are ``used up.''


Here is the folder where you can find the implementation of the linked-list stack:

Directory of linked-list-implemented Stack