Java Queues and Lists Implementation using Interfaces and Classes, Study notes of Computer Science

An example of how to design and implement queues and lists in java using interfaces and classes. The definition of a queue interface and its implementation classes q1, q2, and q3, as well as a list interface and its implementation class l1. The document also discusses the concept of linked lists and stacks, which are related data structures. The document can be useful for university students taking a data structures course, specifically cs 211.

Typology: Study notes

Pre 2010

Uploaded on 08/31/2009

koofers-user-7cn-1
koofers-user-7cn-1 🇺🇸

9 documents

1 / 8

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
CS 211 Data Structures
Interfaces. (cf “The Java Programming Language” book, ch 4.) These provide
a very natural way to design a specification for code to solve a problem,
think of them as being contracts for classes. Effectively, cracking a problem
can be broken down into designing the solution and then implementing it;
the design stage being stipulated by listing ‘skeletal’ classes having methods
(but no definitions), and the implementation stage being split between
implementing the contracts (classes) and writing code which uses them to
actually solve the problem. Hence a programming team could be divided
into these three groups, allowing them to work largely in parallel once the
design has been set.
Imagine building a spec sheet for a queue ... folk join at the back and are
served (and leave) from the front. Being aggressive, we could insist that
after joining a queue, the only way to leave is from the front. This might
lead to ...
public interface Queue { // note that there aren’t even hints of method definitions below, save for the comments!!!
void joinQ ( Person p ) ; // the person p gets added to the back of the queue
Person leaveQ ( ) ; // to return the person at the front, and then dump them in favour of the next person in line
int getLength ( ) ; // to return the number of people in the queue
boolean isFull ( ) ; // to return true if there’s no room left in the queue
boolean isEmpty ( ) ; // to return true if there’s no-one in the queue
} // end interface Queue
1- interfaces
everything in
an interface
is presumed
public
pf3
pf4
pf5
pf8

Partial preview of the text

Download Java Queues and Lists Implementation using Interfaces and Classes and more Study notes Computer Science in PDF only on Docsity!

CS 211 Data Structures

Interfaces. (cf “The Java Programming Language” book, ch 4.) These provide

a very natural way to design a specification for code to solve a problem,

think of them as being contracts for classes. Effectively, cracking a problem

can be broken down into designing the solution and then implementing it;

the design stage being stipulated by listing ‘skeletal’ classes having methods

(but no definitions), and the implementation stage being split between

implementing the contracts (classes) and writing code which uses them to

actually solve the problem. Hence a programming team could be divided

into these three groups, allowing them to work largely in parallel once the

design has been set.

Imagine building a spec sheet for a queue ... folk join at the back and are

served (and leave) from the front. Being aggressive, we could insist that

after joining a queue, the only way to leave is from the front. This might

lead to ...

public interface Queue { // note that there aren’t even hints of method definitions below, save for the comments!!! void joinQ ( Person p ) ; // the person p gets added to the back of the queue Person leaveQ ( ) ; // to return the person at the front, and then dump them in favour of the next person in line int getLength ( ) ; // to return the number of people in the queue boolean isFull ( ) ; // to return true if there’s no room left in the queue boolean isEmpty ( ) ; // to return true if there’s no-one in the queue } // end interface Queue

  • interfaces 1 everything in an interface is presumed public

CS 211 Data Structures

Note that promising to implement an interface forces (via the compiler) an

implementation of every method listed in that interface (but doesn’t insist on the

method definitions being sensible!) ...

public class Q1 implements Queue { void joinQ ( Person p ) { return ; } Person leaveQ ( ) { return new Person ( “anonymous” ) ; } int getLength ( ) { return Integer. MAX_VALUE ; } boolean isFull ( ) { return true ; } boolean isEmpty ( ) { return true ; } public Q1 ( int n ) { System.out.println ( “This queue is so efficient it takes up almost no space!!!” ) ; } // constructor public Q1 ( ) { this ( -47 ) ; } // equally silly default constructor } // end interface Queue

Sadly, the compiler will be perfectly happy with this! Perhaps rather better might

be ...

public class Q2 implements Queue { private Person [ ] storage ; private int length , front , back , size ; private final int DEFAULT_SIZE = 100 ; void joinQ ( Person p ) { if (! isFull( ) ) { storage [ back++ ] = p ; length++ ; } else System.out.println ( “Sorry, full up” ) ; } // end joinQ method Person leaveQ ( ) { Person temp ; if (! isEmpty( ) ) { temp = storage [ front++ ] ; length-- ; return temp ; } else System.out.println ( “Sorry, queue is empty” ) ; } // end leaveQ method int getLength ( ) { return this.length ; } boolean isFull ( ) { return ( this.back == size ) ; } boolean isEmpty ( ) { return ( length == 0 ) ; } public Q2 ( int n ) { size = n ; storage = new Person [ n ] ; length = 0 ; front = 0 ; back = 0 ; } // hopefully n > 0! public Q2 ( ) { this ( DEFAULT_SIZE ) ; } // or some such default value } // end class Q

  • interfaces 2 front back

CS 211 Data Structures

The nifty thing about this approach is that the queue never gets full (until the computer does!),

and is always being sized dynamically according to need (so no wasted space). Of course,

nothing is ever ideal; so in this case there is some computational overhead in creating each

node, so in a situation where the queue size will remain roughly the same it might be better to

use an array flavour, but where the size changes frequently and significantly, this pointer-based

approach is better. Effectively, each time we add a Person, a Node is created to house them,

and it’s that Node which is tacked onto the end of the queue. Each time a Person leaves, the

pointer (front) advances, so that then nothing is referring to the previous front of the queue, so

that it can be garbage-collected, thus allowing reclamation of space.

  • queues 4 public class Node { private Person data ; // holds the data private Node next ; // points to next in line public Person getData ( ) { return data ; } public void setData ( Person p ) { data = p ; } public Node getNext ( ) { return next ; } public void setNext ( Node n ) { next = n ; } public Node ( Person p , Node n ) { data = p ; next = n ; } public Node ( Person p ) { this ( p , null ) ; } public Node ( ) ( this ( null ) ; } } // end class Node public class Q4 implements Queue { private Node front , back ; private int length ; public void joinQ ( Person p ) { if ( isEmpty ( ) ) { back = new Node ( p ) ; front = back ; } else { back. setNext ( new Node ( p ) ) ; back=back. getNext( ) ; } length++ ; } // end joinQ method public Person leaveQ ( ) { if (! isEmpty( ) ) { Person temp = front. getData ( ) ; front = front. getNext ( ) ; length-- ; return temp ; } else { System. out. println ( “Sorry, I am empty” ) ; return null ; } } // end leaveQ method public int getLength ( ) { return this. length ; } public boolean isFull ( ) { return false ; } public boolean isEmpty ( ) { return ( length == 0 ) ; } public Q4 ( int n ) { length = 0 ; } // n is irrelevant here public Q4 ( ) { this ( 0 ) ; } } // end class Q4 front^ back null

CS 211 Data Structures

A very similar structure, but which allows joining and leaving from anywhere within,

is called a ‘linked list’. This could be implemented with arrays, but we’ll focus on a

similar pointer-based approach, using our existing Node class, and thinking of leaving

being the deletion of a Person from the ‘current’ location, and joining as interposing

a person right after the current spot ...

  • lists 5 public class L1 implements List { private Node header , current ; private int length ; public void join ( Person p ) throws BadInsertionPoint { if ( current == null ) throw new BadInsertionPoint ( ) ; Node temp = new Node ( p , current. getNext( ) ) ; current. setNext ( temp ) ; length++ ; } // end join method public void leave ( ) { if (! isEmpty( ) && inList ( ) ) { getPrevious ( ). setNext ( current. getNext ( ) ) ; length-- ; } else System. out. println ( “Sorry, list is empty” ) ; } // end leave method private Node getPrevious ( ) { for ( Node n = header ; n != null && n. getNext ( ) != null ; n = n. getNext( ) ) if ( n. getNext ( ) == current ) return n ; return null ; } // this return is only reached if no ‘previous’ was found public void setCurrent ( Person p ) { for ( current = header ; current != null ; current = current. getNext( ) ) if ( current. getData ( ). equals ( p ) ) return ; } public boolean inList ( ) { return ( current != null && current != header ) ; } public int getLength ( ) { return this. length ; } public boolean isFull ( ) { return false ; } public boolean isEmpty ( ) { return ( length == 0 ) ; } public L1 ( int n ) { header = new Node ( ) ; length = 0 ; } public L1 ( ) { this ( 0 ) ; } } // end class L public interface List { void join ( Person p ) ; // p inserted after ‘current location’ void leave ( ) ; // the current locn’s content is deleted int getLength ( ) ; // the number of people in the list boolean isFull ( ) ; boolean isEmpty ( ) ; void setCurrent ( Person p ) ; // set ‘cur loc’ to where p is } // end interface List current current temp

null null joining a linked list leaving a linked list

CS 211 Data Structures

Stacks are surprisingly powerful animals - much of what goes on in your computer is

done via stacks (of commands, of values, etc.). However, as quick examples ...

(i) Two ways of writing an arithmetic expression are infix , as in a + (b-c)*(d+e-(f/g))

and postfix (or reverse Polish ), as in a b c - d e + f g / - * +. To evaluate the latter, we

can put the values on a stack, and on seeing an operator, apply it by pulling the top

off the stack (twice) and then putting the newly computed value on the stack ...

(ii) As you might guess from the above, we can also use a stack to convert an infix

to a postfix expression, essentially using the stack as a ‘storage-until-ready’ holding

location ...

  • stacks 7 a b a c b a b-c a d b-c a e d b-c a d+e b-c a f d+e b-c a g f d+e b-c a f/g d+e b-c a d+e - (f/g) b-c a (b-c)* (d+e - (f/g)) a a+(b-c)* (d+e - (f/g)) _- appears
  • appears / appears
  • appears
  • appears
  • appears_
  • (

This will produce the postfix version above from the infix flavour term-by-term under the algorithm: (i) output non-operands immediately (ii) rank operands by strength, so + and - are at the bottom, * and / are next, and “(” is the highest (iii) on reading an operand, pop from the stack (into the output) until seeing a weaker one, then push that operand (iv) on reading a “)”, pop everything from the stack until the “(”, which is discarded (popped but not output) (v) if there’s no more input, then pop from the stack until empty (cf 3.6 of the textbook)

CS 211 Data Structures

Trees are essentially lists on steroids, with nodes having multiple ‘nexts’, a

binary tree having two ‘nexts’ (a left and a right) from each node.

  • trees 8