This homework consists of two problems which have the following goals:
In this problem, you are going to write a class MyString which contains both static and non-static members to manipulate strings of characters, modeled on the Java String class, but implemented using linked lists of nodes which contain single characters. You will use iterative algorithms to manipulate these linked lists to implement an important subset of methods from the Java String class. Here is the interface you must implement, which you should put in a class Stringy.java:
/* File: Stringy.java
* Date: 6/1/13
* Author: Wayne Snyder (snyder@bu.edu)
* Class: CS 112, Summer 01 2013
* Assignment: HW 03
* Purpose: This is an interface specifying a subset of the methods for the Java String class; these
* will be implemented using linked lists of characters.
* Related classes: MyString.java
*/
public interface Stringy {
public char charAt(int index); // Returns the char value at the specified index.
public int compareTo(MyString anotherMyString); // Compares two MyStrings lexicographically. Google to find out
// exact semantics.
public MyString concat(MyString str); // Concatenates a copy of the specified MyString to the end of this MyString.
// If str is empty, just return this MyString; otherwise, make a copy
// of this MyString and append a copy of str to it.
public MyString replace(char oldChar, char newChar); // if oldchar does not occur in this MyString, return this;
// else make a copy of this MyString and replace all occurrences
// of oldChar by newChar
public int indexOf(int ch); // Returns the index within this MyString of the first occurrence of the specified character.
public int indexOf(MyString str); // Returns the index within this MyString of the first occurrence of the specified substring.
public int length(); // Returns the length of this MyString.
public MyString substring(int beginIndex, int endIndex); // Returns a new MyString that is a substring of this string.
// Java doesn't allow static methods in interfaces, but if it did, the two static methods you have
// to implement would look like this:
// public static MyString valueOf(int i); // Returns the MyString representation of the int argument.
// public static int parseInt(MyString s) throws NumberFormatException;
// Returns the integer corresponding to the MyString argument
// or an exception if input is ill-formed
}
The objective here is to provide implementations of these standard String methods, but for your own MyString class. Any question about how your methods should behave can be answered by looking up the corresponding String method and playing around with it a bit---your objective is to have exactly the same functionality. The last method, parseInt(..), is actually a static member of the Integer class, but we will provide it as part of the MyString class. In addition to these methods, you must provide the following two methods which are not listed in the interface:
public String toString() { ..... } ; // Convert this MyString to a regular Java String -- thus, when you simply use your MyString in a place where a String is
// expected, it will simply convert to a String automatically.
public MyString(String str) { ..... }; // The constructor for a MyString; it should take a normal Java String and construct a MyString
All questions about functionality (with an important restriction stated below) can be answered by looking up the documentation for Java Strings; in addition, you MUST adhere to the following requirements:
charAt(..) method using linked list algorithms, and then every other method could be written in terms of charAt(...) without practicing linked lists---not useful for learning purposes!]parseInt(...) method, which checks to see if the input string is legal (i.e., a string of digits, possibly preceeded by a minus sign '-'); if it is not legal, it throws an unchecked exception as shown (we will talk about this in class on Tuesday);BigIntegerCalculator.java which I will provide; "1a34"). For example, here is how I would test the parseInt(...) method: int x = Integer.parseInt("234");
int x1 = MyString.parseInt(new MyString("234"));
System.out.println(x);
System.out.println(x1);
System.out.println();
int y = Integer.parseInt("-234");
int y1 = MyString.parseInt(new MyString("-234"));
System.out.println(y);
System.out.println(y1);
System.out.println();
try {
int z = Integer.parseInt("2a34");
}
catch(NumberFormatException e) {
System.out.println(e.getMessage());
}
try {
int z1 = MyString.parseInt(new MyString("2a34"));
}
catch(NumberFormatException e) {
System.out.println(e.getMessage());
}
This code would print out the following to verify that the two versions of parseInt(...) work the same:
234 234 -234 -234 For input string: "2a34" For input string: "2a34"
You are going to write several recursive methods for manipulating linked lists representing positive integers of unbounded size. In this scheme, an integer such as 234345 is represented by nodes containing integer items which are 0 -- 9 (i.e., digits). In order to accomodate the usual procedure for adding (which proceeds from right to left), we will reverse the list of digits so that the least-significant digits are at the beginning of the list, e.g.,
-> 5 -> 4 -> 3 -> 4 -> 3 -> 2 -> . equals 234345
Unfortunately, you can not define static methods in an interface, so we won't be using an interface for your solution class in this assignment. You must write a class BigInt which contains the following static methods:
// returns true iff the string consists of only the characters '0' - '9' with the first character being a non-zero digit
public static boolean legalBigInt(String s) { ... }
// returns true if the input is a list of single-digit integers, all positive with the last being non-zero
public static boolean legalBigInt(Node<Integer> s) { ... }
// turn a String of digits into a linked list of single-digit ints, with ints in reverse order than in the String (one int = one digit);
// if the input is not legal, as defined above, throw the exception shown
public static Node<Integer> toList(String s) throws BigIntegerStringFormatException { ... }
// turn a linked list of single-digit integers into a String, with ints in reverse order than in the String (one int = one digit)
// if the input is not legal, as defined above, throw the exception shown
public static String toString(Node<Integer> p) throws BigIntegerListFormatException { ... }
// add big ints p and q and return the appropriate list; throws the exception shown if input lists are not legal
public static Node<Integer> add(Node<Integer> p, Node<Integer> q) throws BigIntegerListFormatException { ... }
The class BigInt is simply a "wrapper" for these methods which manipulate linked list integers based on the Node class. Recall that this is one of the purposes of a class.
You must follow these requirements for this problem:
Node<Integer> class and put this at the end of your BigInt.java file;BigIntegerCalculator.java which I will provide. You can mostly solve this problem by introspecting on how you do addition, and then thinking about how this might be implemented using the data structure. But remember that all these examples are using the human-oriented method; you have to write computer -oriented methods that work on reversed lists of digits!
For example, when you add two long integers, you basically have three rows of digits, with the top row being the carry from the previous column (the carry into the first column can be a 0). You add the three numbers in the column, break it into two digits (carry and sum) and write the sum digit down and copy the carry digits into the top of the next column. If one of the numbers is shorter than the other, you may have to keep adding a carry in the other number, e.g.,
110 == carries 934 + 78 ---- 1002
A strong hint is that you should write the add method using a recursive helper method as follows:
public static Node<Integer>add(Node<Integer> p, Node<Integer> q) { return addWithCarry(p, q, 0); } // helper method for previous: add big ints p and q with carry from previous position private static Node <Integer> addWithCarry(Node <Integer> p, Node <Integer> q, int k) { ...... }
You should of course develop both of these problems is in a step-wise fashion. Here is what I would do if I were writing these:
First read the assignment carefully, read through the Notes on Recursion and Linked Lists and the lecture notes from the last week, and read through the documentation for the Java String class. Then, for the first problem:
For the second problem, I would do something similar:
You will be graded on how well you follow the requirements, how your code works with the interactive client, and on the functionality of your code as demonstrated by your unit tests. The basic principle we will follow in grading is that if you do not demonstrate a detail of functionality in your unit test, we will assume that your code does not work on this detail.
Submit the files MyString.java and BigInt.java. The BigInt.java file should also contain, outside the scope of the BigInt class, with default access (not public), the classes for the exceptions and the generic class for Node.