Implementing IntVector and Circular Queue in Java, Assignments of Data Structures and Algorithms

Instructions for implementing the intvector class, a specialized vector for storing integers, and the queuecircular class, a circular queue, in java. The intvector class is based on an array representation, and the queuecircular class uses a mutable linked list. Constructor methods and instance methods for both classes, as well as notes and examples for implementation.

Typology: Assignments

Pre 2010

Uploaded on 08/16/2009

koofers-user-urk
koofers-user-urk 🇺🇸

10 documents

1 / 9

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
CS230 Data Structures Handout # 17
Prof. Lyn Turbak February 26, 2007
Wellesley College Revised March 2, 2007
Problem Set 3
Due: 11:59pm Wednesday, March 7
This is the final draft of PS3, containing both problems.
Exam 1 Notice:
The first exam (a take-home exam) will be posted on the evening of Wed. Mar. 7 and will be
due at 6pm on Fri. Mar. 16. This is a hard deadline. No extensions will be given after
this time. The exam will cover the material in class through Lecture 9 (Mon. Mar. 5), Lab 6
(Tue. Mar. 6), and Problem Sets 1 3. Because you should focus on the exam after it is posted,
it is strongly recommended that you submit PS3 on time (11:59pm Wednesday, March 7).
Overview:
The purpose of this assignment is to give you practice with implementing abstract data types
(ADTs). As usual, it is recommended that you (1) start early and (2) work with a partner (a
different one than you worked with on PS1 and PS2).
Submission:
Each team should turn in a single hardcopy submission packet for all problems by slipping it
under Lyn’s office door by 1:30pm on the due date. The packet should include:
1. a team header sheet (see the end of this assignment for the header sheet) indicating the time
that you (and your partner, if you are working with one) spent on the parts of the assignment.
2. your final version of IntVector.java from Problem 1.
3. a transcript of java IntVector for Problem 1.
4. your final version of QueueCircular.java from Problem 2.
5. a transcript of java QueueCircular for Problem 2.
Each team should also submit a single softcopy (consisting of your entire final ps3 directory)
to the drop directory ~cs230/drop/ps3/username, where username is the username of one of the
team members (indicate which drop folder you used on your hardcopy header sheet). To do this,
execute the following Linux commands in the team member’s account where the code is stored:
cd /students/username/cs230
cp -R ps3 ~cs230/drop/ps3/username/
1
pf3
pf4
pf5
pf8
pf9

Partial preview of the text

Download Implementing IntVector and Circular Queue in Java and more Assignments Data Structures and Algorithms in PDF only on Docsity!

CS230 Data Structures Handout # 17 Prof. Lyn Turbak February 26, 2007 Wellesley College Revised March 2, 2007

Problem Set 3

Due: 11:59pm Wednesday, March 7

This is the final draft of PS3, containing both problems.

Exam 1 Notice: The first exam (a take-home exam) will be posted on the evening of Wed. Mar. 7 and will be due at 6pm on Fri. Mar. 16. This is a hard deadline. No extensions will be given after this time. The exam will cover the material in class through Lecture 9 (Mon. Mar. 5), Lab 6 (Tue. Mar. 6), and Problem Sets 1 – 3. Because you should focus on the exam after it is posted, it is strongly recommended that you submit PS3 on time (11:59pm Wednesday, March 7).

Overview: The purpose of this assignment is to give you practice with implementing abstract data types (ADTs). As usual, it is recommended that you (1) start early and (2) work with a partner (a different one than you worked with on PS1 and PS2).

Submission: Each team should turn in a single hardcopy submission packet for all problems by slipping it under Lyn’s office door by 1:30pm on the due date. The packet should include:

  1. a team header sheet (see the end of this assignment for the header sheet) indicating the time that you (and your partner, if you are working with one) spent on the parts of the assignment.
  2. your final version of IntVector.java from Problem 1.
  3. a transcript of java IntVector for Problem 1.
  4. your final version of QueueCircular.java from Problem 2.
  5. a transcript of java QueueCircular for Problem 2.

Each team should also submit a single softcopy (consisting of your entire final ps3 directory) to the drop directory ~cs230/drop/ps3/username, where username is the username of one of the team members (indicate which drop folder you used on your hardcopy header sheet). To do this, execute the following Linux commands in the team member’s account where the code is stored:

cd /students/username/cs cp -R ps3 ~cs230/drop/ps3/username/

Problem 1 [50]: An Array Implementation of Integer Vectors

The IntVector class We have seen that the Java Vector class is a versatile data structure handy for a wide range of uses. However, unlike arrays, the slots of a Java Vector instance may not directly hold values of primitive data types like int, double, and char. Instead, primitive data must be packaged in an instance of a wrapper class (e.g., Integer, Double, Character) before they are stored in a vector, and must be unpackaged upon extraction. This is both cumbersome for the programmer and inefficient for execution.^1 In this problem, we will explore the implementation of an IntVector class is a specialized kind of vector that can store only integers. The IntVector class has the same kinds of methods as the Vector class, except that wherever a Vector method uses a value of type T, the corresponding IntVector method uses an int. When using the IntVector class to represent a collection of integers, it is not necessary to convert integers to/from instances of the Integer class. We will implement an instance of IntVector using an array of integers. Here is a diagram of one instance of IntVector that contains, in order, the three integers 17, 0, and 42:

The elts instance variable points to an integer array that stores the elements of the vector. The number of slots in the array (known as the capacity of the vector) can be any number greater than or equal to the number of elements in the vector. The size instance variable indicates the number of slots (from left to right, starting at slot 0) that contain the elements of the vector. The remaining slots are extra space for the vector to “grow into”. These extra slots may contain any integers whatsoever; their values do not matter because they are ignored by the IntVector methods. We shall refer to the values of these extra slots as “garbage”. In the above example, the size of 3 indicates that only slots 0 through 2 hold vector elements and slots 3 and 4 hold garbage. We will assume that as long as the number of elements in the vector remains less than or equal to the capacity, the array held by the elts variable does not change. In this case, vector operations that change, add, or remove elements must rearrange the elements within the slots of the existing array. For instance, performing v.add(-9) and then v.add(2,230) on the above vector representation should change the state of the objects as follows, where the fact that the array label has not changed indicates that it is the same array as in the previous diagram.

(^1) Java 1.5 has a so-called autoboxing feature (see http://java.sun.com/j2se/1.5.0/docs/guide/language/ autoboxing.html) that can automatically perform the packaging and unpackaging for the programmer, thus making wrapper classes less cumbersome. However, the wrapping is still performed, so the inefficiency still remains.

// Instance Methods public boolean add (int elt); // Note: always returns true. public void add (int index, int elt); public int capacity(); public void ensureCapacity (int minCapacity); public int get (int index); public int indexOf (int elt); public int remove (int index); public void removeAllElements(); public boolean removeElement (int elt); public int set (int index, int elt); public int size ();

Implementing the IntVector Class Your task in this problem is to implement the IntVector class using the “extensible array” rep- resentation discussed above. You should flesh out the skeletons for the above constructor methods and instance methods in the IntVector class in the file ~/cs230/ps3/IntVector.java. Invoking java IntVector tests your implementation on a suite of test cases. The test cases will be run on vectors whose (initialCapacity, capacityIncrement are (1,1), (2,8), (3,0), and (0,0).

Notes

  • The IntVector(int capacityIncrement) and IntVector() constructor methods can invoke the IntVector(int initialCapacity, int capacityIncrement) constructor method us- ing a two-argument this() method.
  • The case where both the capacity and capacityIncrement are 0 is problematic, since doubling 0 yields 0 rather than a larger capacity! Your code needs to handle this case. (Hint: Using ensureCapacity whenever you want to increase the size of the array is helpful for addressing this problem.)
  • Your code will need to indicate an error when an index is not within the valid indices of the vector in the get, set, (two-argument) add, and remove methods. To do this you should use the follow statement:

throw new ArrayIndexOutOfBoundsException(message );

where message is a string indicating the specific error message.

  • The add(int index, int elt) method inserts elt at index index and causes the indices of all other elements in slots index and above to be incremented. This requires shifting such elements rightward in the array. Similarly, remove(int index) and removeElement() can cause elements to be shifted leftward in the array.
  • Carefully check the results of java IntVector to verify that your operations are working as expected. Turn in a transcript of java IntVector as part of your hardcopy submission for this problem.

Problem 2 [50]: Circular Queues In Lecture 9, we saw that a queue can be efficiently represented as a mutable list as long as it maintains two pointers to the list: a front pointer to the first node of the list (where elements are dequeued) and a back pointer to the last node of the list (where elements are enqueued). In this problem, we shall see that it is possible for a queue representation to use just a single back pointer if we represent the queue as a circular list (a.k.a. a cyclic list) – i.e., a list that wraps back on itself. For instance, in this representation, enqueuing A, B, and C in order onto an initially empty queue would lead to a sequence structures depicted by the box-and-pointer diagrams in Fig. 1.

QueueCircular back •

QueueCircular back A

QueueCircular back A^ B

QueueCircular back A^ B^ C

Figure 1: Enqueuing the elements A, B, and C onto an initially empty circular queue.

In the diagrams, the elements stored in the heads of the nodes never change. However, the tails of nodes are rewired to give the depicted structure. In all but the empty queue case, the back instance variable of a QueueCircular instance holds a pointer to the back node of the queue (the node holding the most recently enqueued element). This facilitates enqueueing a new back node as well as dequeuing the front (least recently enqueued) node, which is always the tail of the back node.

  1. In the surgical approach, you first temporarily modify back so that it is no longer cyclic, perform appropriate operations, and then make back cyclic again before returning the result.
  2. In the non-surgical approach, you directly manipulate back as a cyclic list. When traversing back using this approach, you must be sure to include an appropriate stop- ping condition. If you neglect to do this, you will get an infinite recursion, and your program will crash! The best way to debug an infinite recursion is to insert lots of System.out.printlns in your code, and use these to pinpoint which part of your code is causing the infinite recursion. For the non-surgical approach, it is helpful to know that == tests for pointer equality of list nodes – it returns true only when two nodes are exactly the same object object in ObjectLand (i.e., they were created by the same invocation of prepend). Because a queue may contain more than one copy of given element, it is not correct to compare list nodes by their head elements! Instead, used == on the list nodes themselves.

You are welcome to use either of the above two strategies in your size, copy, and toString methods. You can use different strategies for different methods if you like.

  • Introduce any auxiliary methods that you find helpful.
  • In many of the methods, you will need to treat the case of the empty queue (i.e., where back is the empty list) specially.
  • As discussed in lecture, we could simplify some operations and/or make them more efficient by adding extra instance variables. For instance, the size method would be easier to implement and more efficient if there were a size instance variable. However, for this particular problem, you should not add any extra instance variables – back should be your only instance variable.

Appendix A: The MList class

The MList class contains methods for manipulating mutable linked lists. Instances of this class are linked lists whose elements have type T. The MList class implements the Iterable interface. The MList class has no constructor methods. The only way to create MList instances is by using the prepend and empty class methods. The MList class has only a few public instance methods:

public static String toString (); Returns a string representation of this list, in which parentheses delimit the comma-separated string representations of this list’s elements.

public static Iterator iterator (); Returns an iterator that generates the elements of the list from front to back.

public static boolean equals (Object x); If x is an MList instance, returns true if it has the same length as this list and each element is equal (via the equals() instance method) to the corresponding element of this list. Otherwise returns false.

Most of the methods of the MList class are class methods. Below are some of the class methods of the MList class. For the complete set, see ~/cs230/utils/MList.java.

public static MList empty (); Returns an empty mutable list. This method should always be invoked with an explicit type argument, as in MList.empty().

public static boolean isEmpty (MList L); Returns true if L is an empty list and false otherwise.

public static MList prepend (T elt, MList L); Returns a new mutable list node whose head is elt and whose tail is L.

public static T head (MList L); Returns the head of the list L.

public static MList tail (MList L); Returns the tail of the list L.

public static void setHead (MList L, T newHead); Changes the head of the list L to be newHead.

public static void setTail (MList L, MList newTail); Changes the tail of the list L to be newTail.

public static void setTail (MList L, MList newTail); Changes the tail of the list L to be newTail.

public static String toString (MList L); Returns a string representation of the list L, in which parentheses delimit the comma-separated string representations of the L’s elements.

public static boolean equals (MList L1, MList L2); Returns true if L1 and L2 have the same length and each element of L1 is equal (via the equals() instance method) to the corresponding element of L2. Otherwise, returns false.

public static int length (MList L); Returns the number of nodes in L.

public static MList lastNode (MList L); Returns the last node of a non-cyclic list L. Raises an exception if L is empty.

public static MList copy (MList L); Returns a shallow copy of L. The result consists of new MList nodes that share the same elements as L.