Tutorial 2
Tutorial 2
Languages and their naming conventions There is a well-known convention in Java, where method
names (and variable names) are in camel case; that is the words are concatenated, and each (except
the first) starts with a Capital letter. In Python, the convention is to name methods and variables where
words are separated by an underscore character. So a Java method might be getElement, and in
Python we would call this get_element. In this course, we will often adopt the Java convention
in our explanations; but when you are writing code, you should follow the convention of whatever
language you are using. So to do an exercise in Python, you would write a method get_element
even if our instructions speak about getElement.
1 Positional Lists
A positional list is an ADT which consists of a linear sequence of positions, each of which stores an
element. When the structure of the positional list is changed (for example, by insertion of a new item
somewhere), the positions continue to store the same element, unlike an index.
1
COMP2123/2823/9123
insertBefore(p, e): Insert a new element e into the list before position p.
insertAfter(p, e): Insert a new element e into the list after position p.
remove(p): Remove from the list the element at position p.
In an upcoming exercise you will implement the positional list ADT methods for a linked positional
list, but first we will warm up with an exercise on paper.
p1 p2 p3
Here each three-cell rectangle represents a node object. From left to right, the cells represent:
• The element stored by the node (in this case, each node stores a one-character string);
We also have three reference variables, p1, p2, and p3, which refer to different nodes in the list.
Consider the following sequence of statements given in pseudocode below. Show the output that is
printed when this pseudocode is applied to the linked list given in the diagram above, and draw the
resulting state at the end of this sequence. (Be warned, the resulting state is not a nicely-formed
doubly-linked list, unlike the state at the beginning.)
1 print(p2.getElement())
2 print(p3.getNext().getElement())
3 p1.setNext(p3.getNext())
4 p2.getPrev().setElement("f")
5 p2.getNext().getNext().setNext(p2.getNext())
6 p1.setPrev(new Node(p1,"g",p2))
7 p2 = p3
8 print(p1.getNext().getPrev().getElement())
Attempt the exercise yourself on paper, and also go over the solution with your tutor in class.
A scaffold is provided in the workspace for this exercise in the Assessments section on Ed. It contains
the following:
• Position. In Java, this is an interface; In Python it is an abstract base class. This describes
the methods required by the position ADT. You should not edit this interface or class.
• PositionalList. In Java, this is an interface; In Python it is an abstract base class. This
describes the methods required by the positional list ADT. You should not edit this interface or
class.
• Node class. In Java this implements the Position interface and is a nested class within
the LinkedPositionalList skeleton code. In Python it inherits from the Position abstract base
class, and has been coded in the same file as LinkedPositionalList skeleton code. This has
been implemented for you, it includes some suitable methods and variables to be used in a
doubly-linked list implementation of PositionalList. You do not need to edit this class.
• LinkedPositionalList class. In Java this implements the PositionalList interface,
while in Python it inherits from the PositionalList abstract base class. The fields and
constructor have been implemented for you, but you will need to implement all of the other
methods that we have defined in the skeleton code.
You need to implement all of the methods defined by the positional list ADT:
When you have a lot of methods that do similar things, you can often make your code much easier to
write and maintain by using a helper method. In this exercise, you might find it very useful to create
a method which inserts an element between two nodes:
insertBetween(p, q, e): Insert a new element e into the list between position p and
position q.
1.6 Discussion
Sentinels: header and trailer Similar to the textbook and lecture slides, our implementation keeps
sentinel nodes at each end of the list (look in the constructor to see how this is happening). These
sentinel nodes are not part of the list of elements being stored, so don’t count them as part of the size,
and your code should never return them. If a method should return a position outside list, then return
null instead.
Using sentinels can make code much simpler, because they remove lots of special cases that we’d
otherwise have to code for. For example, inserting a new element before the first element of the list
can follow the same algorithm as inserting one in the middle, instead of being a special case we have
to code for.
Error checking In Section 7.3.3 of the textbook Data Structures and Algorithms in Java (6th edition)
by Goodrich, Tamassia and Goldwasser you can find definitions, and implementations of, very similar
interfaces to the ones we are using in this week’s tutorials. However, we have simplified the interfaces
somewhat, so that our implementations can also be a bit simpler than the corresponding ones in the
textbook.
The simplifications we’ve made to the interface involve removing all the error checking (e.g. are
the Positions part of the right type of list, are the Positions being used still valid, etc.) It is good
programming practice to have these sorts of checks. Because we are much more interested in studying
how the data structure works, rather than engineering highly defensive code, we have decided to focus
our attention on the former in this tutorial!
A queue is an ADT which consists of a collection of objects which can be inserted and removed
according to a First-In First-Out (FIFO) principle.
For the next exercises, you may use the java.util.Deque type from the Java Collections Framework
(JCF) if you are using Java, and the collections.deque type if you are using Python. Note that
java.util.Deque is only an interface. A suitable implementing class of Deque is java.util.ArrayDeque.
A deque (pronounced "deck", short for "double-ended queue") can be thought of as "simultaneously
a stack and a queue". Since they admit similar implementations, collections libraries often forgo
separate stack and queue implementations in favour of a deque implementation. Despite this, it tends
to be more conceptually useful to invoke the stack and queue ADTs when designing algorithms and
systems.
You can find the workspace for this exercise in the Challenges section on Ed. Implement the method
isPalindrome using a stack and/or queue to check whether a given word is a palindrome (case-
sensitive). Use the Python or Java scaffold provided.
The main function of both implementations are already written for you. The main function reads in
every line of the standard input, calls the method you have to complete, and then prints out whether
each line is a palindrome or not.
You can find the workspace for this exercise in the Challenges section on Ed. Using your isPalindrome
from the Palindromes exercise, implement the method isPalindromeSentence. Use the Python
or Java scaffold provided.
The main function of both implementations are already written for you. The main function reads in
every line of the standard input, calls the method you have to complete, and then prints out whether
each line is a palindrome sentence or not.
limit the depth to which recursive method calls can go, at which point a java.lang.StackOverflowError
would be thrown. Instead of writing recursive code, which is then executed by the language runtime
using an internal stack, the programmer can write the function iteratively, accessing an explicit stack
within their code.
You can find the workspace for this exercise in the Challenges section on Ed. Implement the getSequence
method in either the Python or Java scaffold provided, without using recursion. It should return a stack
containing the Fibonacci numbers from f (0) up to and including f (n), with f (n) as the top element.
For example:
getSequence(3) should return the stack containing (0, 1, 1, 2) (in that order; bottom to top)
getSequence(5) should return a stack containing (0, 1, 1, 2, 3, 5)