11. LinkedStack
The
Stack
was defined with an interfaceAn array based implementation of the stack was created —
ArrayStack
Now, being aware of linked structures, a linked based stack may be implemented —
LinkedStack
11.1. Stack ADT
Remember, based on the interface, a stack must implement the following methods
push
pop
peek
isEmpty
size
Also remember that the interface strictly defines the what and says nothing about the how
11.2. Implementing a Stack with a Linked Structure
The top of the stack will be managed by a field called
top
that is a reference to the head of a linked structureAll pushing and popping will happen at the head end of the linked structure
An additional field will be needed to keep track of the size of the stack
11.3. Implementation
5/**
6 * Implementation of a stack with a linked structure as the container. The class contains a static inner class defining
7 * a node for the linked structure.
8 *
9 * @param <T> Type of elements that are to be in the stack
10 */
11public class LinkedStack<T> implements Stack<T> {
12
13 private Node<T> top;
14 private int size;
15
16 /**
17 * Create an empty LinkedStack.
18 */
19 public LinkedStack() {
20 top = null;
21 size = 0;
22 }
Like the
ArrayStack
, theLinkedStack
will implement theStack
interfaceThe constructor creates an empty stack with nothing in it
11.3.1. Push
27 @Override
28 public boolean push(T element) {
29 Node<T> toPush = new Node<T>(element);
30 toPush.setNext(top);
31 top = toPush;
32 size++;
33 return true;
34 }
In
push
, notice how this is just adding to the front of a linked structure
11.3.2. Pop
& Peek
38 @Override
39 public T pop() {
40 if (isEmpty()) {
41 throw new NoSuchElementException("Empty stack");
42 }
43 T returnElement = top.getData();
44 top = top.getNext();
45 size--;
46 return returnElement;
47 }
48
49 @Override
50 public T peek() {
51 if (isEmpty()) {
52 throw new NoSuchElementException("Empty stack");
53 }
54 return top.getData();
55 }
Like the
ArrayStack
, popping or peeking from an empty stack throws an exceptionNotice how
pop
does a remove/delete from the front of a linked structure
11.3.3. size
and isEmpty
59 @Override
60 public boolean isEmpty() {
61 return size() == 0;
62 }
63
64 @Override
65 public int size() {
66 return size;
67 }
The
LinkedStack
is empty if itssize() == 0
How else could this condition be checked?
11.3.4. toString
71 @Override
72 public String toString() {
73 StringBuilder builder = new StringBuilder();
74 Node<T> currentNode = top;
75 while (currentNode != null) {
76 builder.append(currentNode.getData());
77 builder.append(", ");
78 currentNode = currentNode.getNext();
79 }
80 return builder.toString();
81 }
This is matching the output format that the
ArrayStack
'stoString
had
11.3.5. equals
& hashCode
85 @Override
86 public boolean equals(Object o) {
87 if (this == o) {
88 return true;
89 }
90 if (o == null || getClass() != o.getClass()) {
91 return false;
92 }
93 LinkedStack<?> that = (LinkedStack<?>) o;
94 if (this.size() != that.size()) {
95 return false;
96 }
97 Node<?> thisCurrent = this.top;
98 Node<?> thatCurrent = that.top;
99 while (thisCurrent != null && thatCurrent != null) {
100 if (!Objects.equals(thisCurrent.getData(), thatCurrent.getData())) {
101 return false;
102 }
103 thisCurrent = thisCurrent.getNext();
104 thatCurrent = thatCurrent.getNext();
105 }
106 return true;
107 }
108
109 @Override
110 public int hashCode() {
111 int result = Objects.hashCode(size);
112 Node<?> current = top;
113 while (current != null) {
114 result = result * 97 + Objects.hashCode(current.getData());
115 current = current.getNext();
116 }
117 return result;
118 }
11.4. Nested Node Class
Consider the doubly linked structure
Since this structure need a reference to both the
next
andprevious
nodes, the existingNode
class will not workAlso consider that the
Node
class would only be used for a linked implementation of somethingAs far as the user of a
LinkedStack
is concerned, they don’t care about theNode
class, they just care that theLinkedStack
worksI don’t know, I don’t want to know
Similar idea to the private method
expandCapacity
in theArrayStack
Does it make sense to have the
Node
class accessible from everywhere?
11.4.1. Nested Classes
Thinking about the doubly linked structure, what should the node class be called,
Node
?This would be a problem if there already exists a
Node
class
Instead, the
Node
class can be put inside theLinkedStack
classIf this is done, the
Node
class can still be accessed by theLinkedStack
classBut, it’s only accessible from within that class, so it keeps the
Node
class out of the way of all other classes
Going back to the doubly linked structure, a
Node
class can exist within the class using the doubly linked structureIt will not introduce any ambiguity since the singly linked and doubly linked structure’s
Node
classes are nested within their respective classes
Perhaps this is not that big of a problem, and there are other ways around it
But since the two classes are inextricably connected, nesting
Node
makes sense
11.4.2. Nesting in LinkedStack
Below is an example of the nested
Node
class at the end of theLinkedStack
classNotice that it is both
private
andstatic
122 /**
123 * A node class for a singly linked structure. Each node contains a nullable reference to data of type T, and a
124 * reference to the next/subsequent/successor singly linked node, which may be a null reference.
125 *
126 * @param <T> Type of the data being stored in the node
127 */
128 private static class Node<T> {
129
130 private T data;
131 private Node<T> next;
132
133 public Node() {
134 this(null);
135 }
136
137 public Node(T data) {
138 this.data = data;
139 this.next = null;
140 }
141
142 public T getData() {
143 return data;
144 }
145
146 public void setData(T data) {
147 this.data = data;
148 }
149
150 public Node<T> getNext() {
151 return next;
152 }
153
154 public void setNext(Node<T> next) {
155 this.next = next;
156 }
157 }
11.5. For Next Time
Read Chapter 4 Section 6
13 pages
11.5.1. Playing Code
Download and play with
One could use the same code from
PlayingArrayStack
to play with theLinkedStack
Only need to make one change
ArrayStack
->LinkedStack
If everything was done correctly, the following code from
PlayingLinkedStack
should work
1import java.util.NoSuchElementException;
2
3public class PlayingLinkedStack {
4 public static void main(String[] args) {
5 // Create a LinkedStack
6 Stack<Integer> myStack = new LinkedStack<>();
7
8 // Check stack is empty
9 System.out.println(myStack.size());
10 System.out.println(myStack.isEmpty());
11 System.out.println(myStack);
12
13 // Test push
14 myStack.push(0);
15 myStack.push(1);
16 myStack.push(2);
17 myStack.push(3);
18 myStack.push(4);
19 System.out.println(myStack.size());
20 System.out.println(myStack.isEmpty());
21 System.out.println(myStack);
22
23 // No test for expandCapacity since LinkedStack
24 // doesn't need it, but test more pushes anyways
25 // as the functionality does not change either way
26 myStack.push(10);
27 myStack.push(11);
28 myStack.push(12);
29 myStack.push(13);
30 myStack.push(14);
31 System.out.println(myStack.size());
32 System.out.println(myStack.isEmpty());
33 System.out.println(myStack);
34
35 // Test peek
36 System.out.println(myStack.peek());
37 System.out.println(myStack.size());
38 System.out.println(myStack.isEmpty());
39 System.out.println(myStack);
40
41 // Test Pop
42 System.out.println(myStack.pop());
43 System.out.println(myStack.pop());
44 System.out.println(myStack.pop());
45 System.out.println(myStack.pop());
46 System.out.println(myStack.pop());
47 System.out.println(myStack.pop());
48 System.out.println(myStack.pop());
49 System.out.println(myStack.pop());
50 System.out.println(myStack.pop());
51 System.out.println(myStack.pop());
52 System.out.println(myStack.size());
53 System.out.println(myStack.isEmpty());
54 System.out.println(myStack);
55
56 // Test peek and pop throwing exception
57 try {
58 myStack.peek();
59 } catch (NoSuchElementException e) {
60 e.printStackTrace();
61 }
62 try {
63 myStack.pop();
64 } catch (NoSuchElementException e) {
65 e.printStackTrace();
66 }
67 }
68}