The push method is like the version of the List add method
that adds an object to the end of the list
(because items are always pushed onto the top of the stack).
Note that it is up to us as the designers of the Stack class to decide
which end of the array corresponds to the top of the stack.
We could choose always to add items at the beginning of the array, or
always to add items at the end of the array.
However, it is clearly not a good idea to add items at the beginning of the
array since that requires moving all existing items;
i.e., that choice would make push be O(N) (where N is the
number of items in the stack).
If we add items at the end of the array, then push is O(1),
except when the array is full.

Here are before and after pictures, illustrating the effects of a call
to push:

The peek method is very similar to the pop method,
except that it only returns the top-of-stack value without changing
the stack.
The size method simply returns the value of numItems, and the
empty method returns true iff numItems is zero.

The signatures of the methods of the Stack class are independent of
whether the stack is implemented using an array or using a linked list;
only the type of the items field needs to change:

private Listnode items; // pointer to the linked list of items in the stack

As discussed above, an important property of stacks is that items
are only pushed and popped at one end (the top of the stack).
If we implement a stack using a linked list, we can choose which end of
the list corresponds to the top of the stack.
It is easiest and most efficient to add and remove items at the front
of a linked list,
therefore, we will choose the front of the list as the top of the stack
(i.e., the items field will be a pointer to the node that contains the
top-of-stack item).
Below is a picture of a stack represented using a linked list; in this
case, items have been pushed in alphabetical order, so "cc" is at the top
of the stack:

Notice that, in the picture, the top of stack is to the left (at the front of
the list), while for the array implementation, the top of stack was to
the right (at the end of the array).

Let's consider how to write the pop method.
It will need to perform the following steps:

Check whether the stack is empty; if so, throw an EmptyStackException.

Remove the first node from the list by setting items = items.next.

Decrement numItems.

Return the value that was in the first node in the list.

Note that by the time we get to the last step (returning the top-of-stack
value), the first node has already been
removed from the list, so we need to save its value in order to return it
(we'll call that step 2(a)).
Here's the code, and an illustration of what happens when pop
is called for a stack containing "cc", "bb", "aa" (with "cc" at the
top).

Now let's consider the push method.
Here are before and after pictures, illustrating the effect of a call
to push when the stack is implemented using a linked list:

The steps that need to be performed are:

Create a new node whose data field contains the object to be pushed
and whose next field contains a pointer to the first node in the
list (or null if the list is empty). Note that the value for the
next field of the new node is the value in the Stack's items
field.

Fill in the following table, using Big-O notation to give the
worst-case times for each of the stack methods for a stack of size N,
assuming a linked-list implementation.
Look back at the table you filled in for the array implementation.
How do the times compare?
What are the advantages and disadvantages of using an array vs using a
linked list to implement the Stack class?