S-22 Sample Problems
Overview
The following sample problems offer a sense of the level of programming proficiency that is required of students who are planning to take S-22 Data Structures. If you do not have the necessary level of proficiency, you may want to consider first taking Computer Science E-10b.
Problem 1 Array practice
Write a method with the header
public static void swapPairs(int[] arr)
that takes a reference to an array of integers arr and swaps adjacent pairs of
elements: arr[0] with arr[1], arr[2] with arr[3], etc. For example,
consider this array:
int[] values = {0, 2, 4, 6, 8, 10};
After calling swapPairs(values), the contents of the values array should be
{2, 0, 6, 4, 10, 8}. In an odd-length array, the last element should not be
moved. If the parameter is null, the method should throw an
IllegalArgumentException.
Problem 2 Object-oriented programming
In this problem, you will implement two classes that could be used as building
blocks for programs that manage someone’s appointments and contacts: a class
called Date that serves as a blueprint for objects that represent a single
date, and a class called Person that serves as a blueprint for objects that
represent a single person. In addition, you will implement one method from a
client program that uses these two blueprint classes. The sections below outline
the steps that you should take.
-
(0 points) Download Date.java and put this file in the folder/directory that you’re using for your work on this assignment. This file includes some starter code for the
Dateclass the you will write, and we encourage you to read through this code before continuing. In particular, make sure that you understand each of the class constants that we have given you, reading the comments that accompany them. -
Implement two static helper methods
InDate.java, we have given you the code for one “helper” method calleddayOfWeekNumber. The method takes three parameters —a month number, a day number, and year —and it returns the number of the day of the week on which the corresponding date falls: 0 for Sunday, 1 for Monday, 2 for Tuesday, etc. For example, November 28, 2013 falls on a Thursday, and thusdayOfWeekNumber(11, 28, 2013)returns 4. (You do not need to understand the algorithm that this method uses.)You should implement two other static helper methods:
-
isLeapYear: it should take a year as a parameter, and it should returntrueif the year is a leap year andfalseif it is not. Most years that are divisible by 4 are leap years. The one exception is years that are divisible by 100 and not divisible by 400; they are not leap years. For example, 1900 was not a leap year because it is divisible by 100 and not divisible by 400. 2000 was a leap year because it is divisible by 400. (Hint: You can use the modulus operator (%) to determine if a year is divisible by 4, 100, or 400.) -
numDaysInMonth: it should take a month number and year as parameters, and it should return the number of days in the specified month. This method should make use of theNUM_DAYSarray that we have given you. When necessary, it should also take into account whether the specified year is a leap year. For example,numDaysInMonth(2, 2012)should return 29, because there were 29 days in February in 2012.
You should implement these methods now before continuing, because you will use them in some of the other methods that you will write below.
Note that these methods (unlike the other methods that you will write) are static, because they don’t access the fields inside an object. Rather, they only make use of the values passed in as parameters. Although these methods are helper methods, you should make both of them public, so that they can be called from outside the class.
-
-
Define the fields for
Dateobjects
Below the starter code inDate.java, add field definitions that allow aDateobject to capture the following information:- the number of the month (an integer: 1 for January, 2 for February, etc.)
- the day of the month (an integer)
- the year (an integer).
For example, here is what a
Dateobject representing November 28, 2013 (Thanksgiving!) would look like in memory:+----------------+ | +------+ | | month | 11 | | | +------+ | | +------+ | | day | 28 | | | +------+ | | +------+ | | year | 2013 | | | +------+ | +----------------+Note that it has three fields, each of which is an
int.For now, you only need to define the fields, making sure to protect them from direct access by client code. In the next section, you will write a constructor that assigns values to the fields and ensures that only valid values are allowed.
-
Implement a
Dateconstructor
Next, write a constructor forDateobjects that takes three integer parameters specifying (in this order) the month, day, and year. It should ensure that only valid values are assigned to the object’s fields, and it should throw an exception if the specified date is invalid. It should do the error-checking itself, because there will be no separate mutator methods forDateobjects. In particular, it should ensure that:- the year is 1583 or later (a limitation stems from the fact that the Gregorian calendar was first used in October of 1582). We have given you a class constant called
MIN_YEARfor this smallest year. - the month is between 1 and 12
- the day is an integer between 1 and the number of days in that month. Take advantage of one of the helper methods that you wrote for part 2.
-
Implement the basic
Dateaccessor methods
Once you have defined the fields and constructor, you should then write the following initial set of accessor methods:-
getMonth, which returns the month component of aDateobject as an integer. For theDateshown above, the method would return 11. -
getDay, which returns the day component of aDateobject as an integer. For theDateshown above, the method would return 28. -
getYear, which returns the year component of aDateobject as an integer. For theDateshown above, the method would return 2013. -
monthName, which returns the name of aDateobject’s month. For theDateshown above, the method would return the string"November". This method should make use of the array of month names that we have given you as a class constant. Hint: You should be able to write a single statement that returns the appropriate element of that array. -
dayOfWeekName, which returns the name of the day of the week on which aDatefalls. For theDateshown above, the method would return"Thursday". This method should make use of the array of day names that we have given you as a class constant, as well as thedayOfWeekNumberhelper method (see part 2). -
a
toStringmethod that returns aStringrepresentation of aDateobject. The returnedStringshould have the form “day_of_week, month_name day, year”. For theDateshown above, the method would return"Thursday, November 28, 2013". Like thetoString()method that we discussed in lecture, this method should not do any printing; it should simply return the appropriate string.
Note that all of these methods are accessor methods. Our
Dateobjects are immutable — they cannot be changed after they are created — and thus they have no mutator methods.Make sure that your methods are non-static, because they need to access the fields in the calling object.
You are now ready to use the first client program to test the code you have written thus far. See the section entitled Client programs below.
-
-
Add methods for comparing two
Dateobjects
Define three non-static methods that allow a client to compare twoDateobjects:-
an
equalsmethod that takes aDateobject as a parameter and determines if it is equivalent to the calling object, returningtrueif it is equivalent andfalseif it is not equivalent. TwoDateobjects should only be considered equivalent if they have the same values for each of the components (month, day, and year). If a value ofnullis passed in for the parameter, the method should returnfalse. -
a method named
isBeforethat takes aDateobject as a parameter and returnstrueif the calling Date object comes before theDatepassed in as a parameter andfalseif it does not. For example, consider the followingDateobjects:Date d1 = new Date(12, 31, 2013); // represents December 31, 2013 Date d2 = new Date(1, 1, 2014); // represents January 1, 2014d1.isBefore(d2)should returntrue, whereasd2.isBefore(d1),d1.isBefore(d1), andd2.isBefore(d2)should all returnfalse. If a value ofnullis passed in for the parameter, the method should returnfalse. -
a method named
isAfterthat takes aDateobject as a parameter and returnstrueif the callingDateobject comes after theDatepassed in as a parameter andfalseif it does not. Note: If you take advantage of other methods that you are writing, this method should be very simple! If a value ofnullis passed in for the parameter, the method should returnfalse.
You are now ready to use the second client program to test the code you have written for part 6. See the section entitled Client programs below.
-
-
Define the fields for
Personobjects
Create a new filePerson.java, in which you will create a blueprint class forPersonobjects. After specifying the class header, add field definitions that allow aPersonobject to capture the following information:- the person’s name (a
Stringobject) - the person’s date of birth (a
Dateobject)
Note that the
Personclass makes use of theDateclass that you defined above. For now, you only need to define the fields, making sure to protect them from direct access by client code. -
Implement a
Personconstructor
Next, add a constructor forPersonobjects that takes two parameters: aStringfor the person’s name and aDatefor the person’s date of birth (in that order). It should ensure that neither parameter isnull, and that the string specifying the name is not empty, and it should throw an exception as needed. It should do the error-checking itself, because there will be no separate mutator methods forPersonobjects.Here is one example of how the constructor will be used:
Person kate = new Person("Kate Winslet", new Date(10, 5, 1975));The variable
katenow represents the actress Kate Winslet, who was born on October 5, 1975. -
Implement the
Personaccessor methods
Once you have defined the fields and constructor, you should then write the following set of accessor methods:-
getName, which returns thePerson‘s name as aString. -
getDOB, which returns thePerson‘s date of birth as aDate. -
getBirthdayIn, which takes an integer parameter representing a year, and creates and returns aDateobject representing the date on which the person’s birthday falls in that year. In other words, it should construct and return aDateobject with the same month and day as the person’s date of birth, but with the specified year instead of the year in which the person was born. For example, given thePersonobjectkatedefined above,kate.getBirthdayIn(2013)should return aDateobject representing 10/5/2013, which was the date of Kate Winslet’s birthday this year. The specified year can be before the year in which the person was born. The only problematic parameter values are years that are smaller than the minimum year forDateobjects, but theDateconstructor will already check for those, so this method won’t need to perform any error-checking of its own.-
You will need to use the
Dateconstructor to construct the newDateobject that the method will return. -
To obtain the necessary month and day, you will need to make method calls using the
Dateobject that represents the person’s date of birth — i.e., theDateobject that is stored inside thePersonobject. Note that your code cannot access the fields of theDateobject directly, because those fields are private members of another class. That’s why you will need to call the appropriate accessor methods in theDateobject.
-
-
getAgeOn, which takes a parameter of typeDateand returns an integer representing the person’s age in years on that date.-
If the specified
Dateis before the person’s date of birth, the method should throw an exception. -
The method should take into account all components (month, day and year) of the
Person‘s date of birth and the specifiedDateparameter when determining the person’s age on that date. For example, consider the followingDateobjects:Date july4 = new Date(7, 4, 2013); Date birthday = new Date(10, 5, 2013); Date thanksgiving = new Date(11, 28, 2013);If
kateis still thePersonobject mentioned above,kate.getAgeOn(july4)should return 37 — because 7/4/2013 was before Kate Winslet’s birthday in 2013, when she turned 38 — whereaskate.getAgeOn(birthday)andkate.getAgeOn(thanksgiving)should return 38, because the dates specified in those method calls are on or after her birthday in 2013.
-
-
a
toStringmethod that returns aStringrepresentation of aPersonobject. The returnedStringshould have the form “name (born on dob)”, where dob is the String representation of the person’s dob. For thePersonobjectkatedefined above, the method would return"Kate Winslet (born on Sunday, October 5, 1975)". Take advantage of theDatetoString()method, which will produce the necessary string for the date of birth. Here again, this method should not do any printing; it should simply return the appropriate string.
All of these methods are accessor methods. Our
Personobjects are immutable — they cannot be changed after they are created — and thus they have no mutator methods. In addition, we have chosen not to implement our ownequalsmethod for this class, which means that clients of the class will use the defaultequalsmethod when they need to check if twoPersonobjects are equal.Make sure that your methods are non-static, because they need to access the fields in the calling object.
You are now ready to use the third client program. See the section entitled Client programs below.
-
-
Complete the
BirthdayCalculatorclient program
Finally, you will write the code needed to complete the final client program, which reads information from the console about one or more people, and then outputs their birthdays and ages in two different years —the current year, and a year entered by the user. Each age should be the age that the person will turn on their birthday in the corresponding year.We’ve written most of this client program for you in a file named BirthdayCalculator.java. Save this file in the folder/directory that you’re using for your work on this assignment. We recommend that you begin by reading through the code that we’ve given you. You can also run the program in its current form, but you will see that it doesn’t currently print the names, birthdays and ages.
To complete this program, you need to write the body of the method called
printBirthdays. We have given you the header that you should use, and the body of the method currently consists of a temporaryprintlnstatement that indicates that the method is not yet implemented. You should replace thatprintlnwith your implementation.The method takes an array of
Personobjects and a year as parameters, and it should print the names of the people in the array, along with their birthdays and ages in the specified year. See the sample runs for what this method’s output should look like. For full credit, this method should not do unnecessary work. Rather, it should take full advantage of the methods that you implemented for thePersonclass to obtain the information that it needs to print.
Client programs
To help you in testing your classes, we have created several sample client programs:
-
- should compile after completion of parts 1–5. Do not open it before then!
- tests the methods from parts 2, 4 and 5
- if it doesn’t compile, check your method headers
- expected output is given here
-
- should compile after completion of parts 1–6. Do not open it before then!
- tests the methods from part 6
- if it doesn’t compile, check your method headers
- expected output is given here
-
- don’t open it until the
Personclass is completed - if it doesn’t compile, check your
Personmethod headers - expected output is here
-
the BirthdayCalculator.java program. See part 10 for more detail.
Save these files in the same folder/directory as your Date.java and
Person.java files.
Make sure that your constructors and methods are compatible with these client programs. Once you have implemented your classes, the client programs should compile and run without any modification. You may also want to add code to these programs to allow yourself to test your classes more thoroughly.
Implementation guidelines
-
Make sure that your classes provide appropriate encapsulation.
-
Avoid redundant code. Don’t forget that one instance method can call another instance method. Taking advantage of this fact will help you to avoid code duplication and to simplify your code.
-
Employ good programming style. Use appropriate indentation, select descriptive variable names, insert blank lines between logical parts of your program, and add comments as necessary to explain what your code does. In particular, you should add comments to the start of the file and before each method that you write.
Problem 3 Recursion and strings
Note
Prior exposure to recursion is not strictly required, but it is recommended. If you have had little or no prior experience with recursion, you may want to consider taking Computer Science E-10b before you take S-22 Data Structures.
In a file named StringRecursion.java, implement the methods described below,
and then create a main() method to test these methods. Your methods must be
recursive; no credit will be given for methods that employ iteration. In
addition, global variables (variables declared outside of the method) are not
allowed. You may find it helpful to employ the substring, charAt, and
length methods of the String class as part of your solutions.
-
public static void printWithSpaces(String str)This method should use recursion to print the individual characters in the string
str, separated by spaces. For example,printWithSpaces("space")should prints p a c ewhere there is a single space after the
e. The method should not return a value.Special cases: If the value
nullor the empty string ("") are passed in as the parameter, the method should just print a newline (by executing the statementSystem.out.println();) and return. -
public static String weave(String str1, String str2)This method should use recursion to return the string that is formed by “weaving” together the characters in the strings
str1andstr2to create a single string. For example:-
weave("aaaa", "bbbb")should return the string"abababab" -
weave("hello", "world")should return the string"hweolrllod"
If one of the strings is longer than the other, its “extra” characters — the ones with no counterparts in the shorter string — should appear immediately after the “woven” characters (if any) in the returned string. For example,
weave("recurse", "NOW")should return the string"rNeOcWurse", in which the extra characters from the first string — the characters in"urse"— come after the characters that have been woven together.This method should not do any printing; it should simply return the resulting string. If
nullis passed in for either parameter, the method should throw anIllegalArgumentException. If the empty string ("") is passed in for either string, the method should return the other string. For example,weave("hello", "")should return"hello"andweave("", "")should return"". -