CarrCh04v2

CarrCh04v2 - C H A P T E R 4 Lists CONTENTS Specifications...

Info iconThis preview shows page 1. Sign up to view the full content.

View Full Document Right Arrow Icon
This is the end of the preview. Sign up to access the rest of the document.

Unformatted text preview: C H A P T E R 4 Lists CONTENTS Specifications for the ADT List Refining the Specifications Using the ADT List Java Class Library: The Interface List Using a List Is Like Using a Vending Machine PREREQUISITES Introduction Chapter 1 Chapter 3 Appendix B Java Classes Designing Classes Exception Handling OBJECTIVES After studying this chapter, you should be able to G G G Describe the concept of an abstract data type (ADT) Describe the ADT list Use the ADT list in a Java program T his chapter builds on the concepts of encapsulation and data abstraction that were presented in the previous chapter, and it develops the notion of an abstract data type, or ADT. As an example of an abstract data type, we specify and use the ADT list. In doing so we will provide a Java interface for our list. Knowing just this interface, you will be able to use a list in a Java program. You do not need to know how the entries in the list are represented or how the list operations are implemented. Indeed, your program will not depend on these specifics. As you will see, this important program feature is what data abstraction is all about. 79 80 CHAPTER 4 Lists Specifications for the ADT List 4.1 Figure 4-1 A list provides a way to organize data. We can have to-do lists, gift lists, address lists, grocery lists, even lists of lists. These lists provide a useful way for us to organize our lives, as illustrated in Figure 4-1. Each list has a first item, a last item, and usually items in between. That is, the items in a list have a position: first, second, and so on. An item’s position might be important to you, or it might not. When adding an item to your list, you might always add it at the end, or you might insert it between two other items already in the list. A to-do list I have so much to do this weekend — I should make a list. To Do 1. Read Chapter 4 2. Call home 3. Buy card for Sue Everyday lists such as to-do lists, gift lists, address lists, and grocery lists have entries that are strings. What can you do to such lists? G G G G G G G G G G Typically, you add a new entry at the end of the list. Actually, you can add a new entry anywhere: at the beginning, the end, or in between items. You can cross out an entry—that is, remove it. You can remove all entries. You can replace an entry. You can look at any entry. You can determine whether the list contains a particular entry. You can count the number of entries in the list. You can determine whether the list is empty or full. You can display all of the entries in the list. Specifications for the ADT List 81 4.2 When you work with a list, you determine where an entry is or should be. You probably are not conscious of its exact position: Is it tenth? Fourteenth? However, when your program uses a list, a convenient way to identify a particular entry is by the entry’s position within the list. It could be first, that is, at position 1, or second (position 2), and so on. This convention allows you to describe, or specify, the operations on a list more precisely. At this point, you should not be thinking about how to represent a list in your program or how to implement its operations. For the moment, forget about arrays, for example. You first need to clearly know what the list operations do: Focus on what the operations do, not on how they do them. That is, you need a detailed set of specifications before you can use a list in a program. In fact, you should specify the list operations before you even decide on a programming language. At this point, the list is an abstract data type. An abstract data type, or ADT, consists of data having the same type and the operations on that data. An ADT describes its data and specifies its operations. It does not indicate how to store the data or how to implement the operations. Thus, we can discuss ADTs independently of a programming language. In contrast, a data structure is an implementation of an ADT within a programming language. 4.3 To specify the ADT list, we describe its data and specify the operations on that data. Unlike common lists whose entries are strings, the ADT list is more general and has entries that are objects of the same type. The following is a specification of the ADT list: ABSTRACT DATA TYPE LIST DATA G G A collection of objects in a specific order and having the same data type The number of objects in the collection OPERATIONS add(newEntry) Task: Adds newEntry to the end of the list. Input: newEntry is an object. Output: None. add(newPosition, newEntry) Task: Adds newEntry at position newPosition within the list. Input: newPosition is an integer, newEntry is an object. Output: None. remove(givenPosition) Task: Removes from the list the entry at position givenPosition. Input: givenPosition is an integer. Output: None. clear() Task: Removes all entries from the list. Input: None. Output: None. 82 CHAPTER 4 Lists replace(givenPosition, newEntry) Task: Replaces the entry at position givenPosition with newEntry. Input: givenPosition is an integer, newEntry is an object. Output: None. getEntry(givenPosition) Task: Retrieves the entry at position givenPosition in the list. Input: givenPosition is an integer. Output: Returns a reference to the entry at position givenPosition. contains(anEntry) Task: Determines whether the list contains anEntry. Input: anEntry is an object. Output: Returns true if anEntry is in the list, or false if not. getLength() Task: Gets the number of entries currently in the list. Input: None. Output: Returns the number of entries currently in the list as an int. isEmpty() Task: Determines whether the list is empty. Input: None. Output: Returns true if the list is empty, or false if not. isFull() Task: Determines whether the list is full. Input: None. Output: Returns true if the list is full, or false if not. display() Task: Displays all entries that are in the list in the order in which they occur, one per line. Input: None. Output: None. We have only begun to specify the behaviors of these list operations, as the specifications just given leave some details to the imagination. Some examples will help us to better understand these operations so that we can improve the specifications. We’ll need precise specifications before we implement the operations. Programming Tip: After designing a draft of an ADT, confirm your understanding of the operations and their design by writing some pseudocode that uses the ADT. Specifications for the ADT List 4.4 83 Example. When you first declare a new list, it is empty and its length is zero. If you add three objects—a, b, and c—one at a time and in the order given, to the end of the list, the list will appear as a b c The object a is first, and c is last. To save space here, we will sometimes write a list’s contents on one line. For example, we might write a b c to represent this list. The following pseudocode represents the previous three additions to the specific list myList: myList.add(a) myList.add(b) myList.add(c) At this point, myList is not empty, so myList.isEmpty() is false. Since the list contains three entries, myList.getLength() is 3. Notice that adding entries to the end of a list does not change the positions of entries already in the list. Figure 4-2 illustrates these add operations as well as the operations that we describe next. Figure 4-2 The effect of ADT list operations on an initially empty list myList.add(a) myList.add(b) myList.add(c) a a b a b c myList.add(2,d) a d b c 4.5 myList.add(1,e) e a d b c myList.remove(3) e a b c Now suppose that we add entries at various positions within the list. For example, myList.add(2, d) places d at position 2 within the list. Doing so, however, moves b to position 3 and c to position 4, so that the list now contains a d b c 84 CHAPTER 4 Lists If we add e to the beginning of the list by writing myList.add(1, e) the current entries in the list move to the next higher position. The list then contains e a d b c Look at Figure 4-2 again to see the effect of these operations. 4.6 We can retrieve the second entry in this list by writing ref2 = myList.getEntry(2) This expression returns a reference to the second entry. Remember that we are writing pseudocode here. Later examples in Java will show you that a type cast is likely to be necessary. What happens when we remove an entry? For example, myList.remove(3) removes the third entry—d in the previous example—from the list. The list then contains e a b c Notice that entries after the one that was removed move to the next lower position within the list. Figure 4-2 illustrates this change to the list. What if an application requires us to remove an entry from a list but retain the entry for another purpose? Our interpretation of remove would force us to first use getEntry to obtain a reference to the entry and then use remove to remove the entry from the list. We could refine the specification of remove to return a reference to the object removed from the list. To use this version of remove, we would write a pseudocode statement such as ref3 = myList.remove(3) This change makes remove more versatile, as the client could either save or ignore the returned reference. We can replace the third entry b of our list with f by writing myList.replace(3, f) No other entries move or change. We could refine the specification of replace to return a reference to the object that was replaced. So if we wrote ref = myList.replace(3, f) ref would reference the former entry b. Note: The objects in an ADT list have an order determined by the client of the list. To add, remove, or retrieve an entry, you must specify the entry’s position within the list. Refining the Specifications 4.7 The previous specifications ignore at least three difficulties that might arise during the use of the ADT list: G G The operations add, remove, replace, and getEntry are well behaved when the given position is valid for the current list. What happens when one of these operations receives an invalid position number? The methods remove, replace, and getEntry are not meaningful for empty lists. What happens when an empty list invokes one of these operations? Specifications for the ADT List G 85 A list could become full, depending on the list’s implementation. What happens when the client tries to add an entry to a full list? You as class designer need to make decisions about how to handle unusual conditions and include these decisions in your specifications. The documentation for the ADT list should reflect both these decisions and the detail that the previous examples demonstrate. 4.8 In general, you can address unusual situations in several ways. Your method could G G G G G Assume that the invalid situations will not occur. This assumption is not as naive as it might sound. A method could state as an assumption—that is, a precondition—restrictions to which a client must adhere. It is then up to the client to enforce the precondition by checking that the precondition is satisfied before invoking the method. Notice that the client has methods such as isEmpty and getLength to help with this task. As long as the client obeys the restriction, the invalid situation will not occur. Ignore the invalid situations. A method could simply do nothing when given invalid data. Doing absolutely nothing, however, leaves the client wondering what happened. Make reasonable assumptions and act in a predictable way. For example, if a client tries to remove the sixth entry from a three-entry list, the remove method could either remove the last entry instead or return null. Return a boolean value that indicates the success or failure of an operation. Throw an exception. As Appendix B shows, throwing an exception is often a desirable way for a Java method to react to unusual events that occur during its execution. The method can simply report a problem without deciding what to do about it. The exception enables each client to do what is needed in its own particular situation. To handle errors in this way, you must write try-catch blocks to use the method. For simplicity, we adopt the philosophy that methods should throw exceptions only in truly exceptional circumstances, when no other reasonable solution exists. Future chapters will include some examples of handling exceptions. 4.9 After you have identified all unusual circumstances, you should specify how your methods will behave under each of these circumstances. For example, it would be reasonable for the add method to throw an exception if it tries to add an entry at an invalid position. However, it might be just as reasonable for the method to return false in these situations. Your documentation for your ADT should describe these specifications. As your specifications become more detailed, they increasingly should reflect your choice of programming language. Ultimately, you can write a Java interface (see Chapter 3) for the class that will implement the ADT. Note: A first draft of an ADT’s specifications often overlooks or ignores situations that you really need to consider. You might intentionally make these omissions to simplify this first draft. Once you have written the major portions of the specifications, you can concentrate on the details that make the specifications complete. 4.10 The following Java interface contains the methods for an ADT list and detailed comments that describe their behaviors. Recall that a class interface does not include data fields, constructors, private methods, or protected methods. We assume that items in the list will be objects—that is, instances of a class. For example, we could have a list of strings. To accommodate entries of any class type, the list methods use Object as the type of entry. As we discussed previously, all classes ultimately are derived from Object. 86 CHAPTER 4 Lists For lists of primitive types, we could replace each occurrence of Object with the desired type. Another possibility, however, would be to place instances of an appropriate wrapper class in our list. For example, instead of instances of the primitive type int, we could use instances of the wrapper class Integer. (Appendix A discusses wrapper classes.) /** An interface for the ADT list. * Entries in the list have positions that begin with 1. */ public interface ListInterface { /** Task: Adds a new entry to the end of the list. * @param newEntry the object to be added as a new entry * @return true if the addition is successful, or false if not */ public boolean add(Object newEntry); /** Task: Adds a new entry at a specified position within * the list. Entries originally at and above the specified * position are at the next higher position within the list. * The list’s size is increased by 1. * @param newPosition an integer that specifies the desired * position of the new entry; newPosition >= 1 * and newPosition <= getLength()+1 * @param newEntry the object to be added as a new entry * @return true if the addition is successful, or false if not */ public boolean add(int newPosition, Object newEntry); /** Task: Removes the entry at a given position from the list. * Entries originally at positions higher than the given * position are at the next lower position within the list, * and the list’s size is decreased by 1. * @param givenPosition an integer that indicates the position of * the entry to be removed; givenPosition >= 1 * and givenPosition <= getLength() * @return either the entry at position givenPosition, if the removal * was successful, or null */ public Object remove(int givenPosition); /** Task: Removes all entries from the list. */ public void clear(); /** Task: Replaces the entry at a given position in the list. * @param givenPosition an integer that indicates the position of the * entry to be replaced; givenPosition >= 1 * and givenPosition <= getLength() * @param newEntry the object that will replace the entry at the * position givenPosition * @return true if the replacement occurs, or false if either the * list was empty or givenPosition is invalid */ public boolean replace(int givenPosition, Object newEntry); /** Task: Retrieves the entry at a given position in the list. * @param givenPosition an integer that indicates the position of * the desired entry; givenPosition >= 1 * and givenPosition <= getLength() * @return a reference to the indicated list entry, if found, Specifications for the ADT List 87 * otherwise returns null */ public Object getEntry(int givenPosition); /** Task: Determines whether the list contains a given entry. * @param anEntry the object that is the desired entry * @return true if the list contains anEntry, or false if not */ public boolean contains(Object anEntry); /** Task: Gets the length of the list. * @return the integer number of entries currently in the list */ public int getLength(); /** Task: Determines whether the list is empty. * @return true if the list is empty, or false if not */ public boolean isEmpty(); /** Task: Determines whether the list is full. * @return true if the list is full, or false if not */ public boolean isFull(); /** Task: Displays all entries that are in the list, one per * line, in the order in which they occur in the list. */ public void display(); } // end ListInterface Question 1 Write pseudocode statements that add some objects to a list, as follows. First add c, then a, then b, and then d such that the order of the objects in the list will be a, b, c, d. Question 2 Write pseudocode statements that exchange the third and seventh entries in a list of ten objects. Note: The entries in a list of n entries are numbered from 1 to n. Although you cannot add a new entry at position 0, you can add one at position n + 1. 4.11 After specifying an ADT and writing a Java interface for its operations, you should write some Java statements that use the ADT. In this way, you check both the suitability and your understanding of the specifications. It is better to revise the design or documentation of the ADT now instead of after you have written its implementation. An added benefit of doing this task carefully is that you can use these same Java statements later to test your implementation. The following section looks at several examples that use a list. These examples can be part of a program that tests your implementation. Programming Tip: Write a test program before you implement a class Writing Java statements that test a class’s methods will help you to fully understand the specifications for the methods. Obviously, you must understand a method before you can implement it correctly. If you are also the class designer, your use of the class might help you see desirable changes to your design or its documentation. You will save time if you make these revisions before you have implemented the class. Since you must write a program that tests your implementation sometime, why not get additional benefits from the task by writing it now instead of later? 88 CHAPTER 4 Lists Using the ADT List Imagine that we hire a programmer to implement the ADT list in Java, given the interface and specifications that we have developed so far. If we assume that these specifications are clear enough for the programmer to complete the implementation, we can use the ADT’s operations in a program without knowing the details of the implementation. That is, we do not need to know how the programmer implemented the list to be able to use it. We only need to know what the ADT list does. This section assumes that we have an implementation for the list and demonstrates how we can use a list in our program. 4.12 Figure 4-3 Example. Imagine that we are organizing a local road race. Our job is to note the order in which the runners finish the race. Since each runner wears a distinct identifying number, we can add each runner’s number to the end of a list as the runners cross the finish line. Figure 4-3 illustrates such a list. A list of numbers that identify runners in the order in which they finished a race 16 4 33 27 The following Java program shows how we can perform this task by using the ADT list. It assumes that the class AList implements the Java interface ListInterface that you saw in the previous section. Since ListInterface assumes that the items in the list are objects, we will treat each runner’s identifying number as a string. public class ListClient { public static void main(String args) { testList(); } // end main public static void testList() { ListInterface runnerList = new AList(); // has only methods // in ListInterface runnerList.add("16"); // winner runnerList.add(" 4"); // second place Using the ADT List 89 runnerList.add("33"); // third place runnerList.add("27"); // fourth place runnerList.display(); } // end testList } // end ListClient The output from this program is 16 4 33 27 Notice that the data type of runnerList is ListInterface instead of AList. While either type is correct, using ListInterface obliges runnerList to call only methods in the interface. 4.13 Example. The previous example uses the list method display to display the items in the list. We might want our output in a different form, however. The following method is an example of how a client could display the items in a list without using the method display. Notice the use of the list methods getLength and getEntry. Also notice that the data type of the input parameter aList is ListInterface. Thus, we can use as the argument of the method an instance of any class that implements ListInterface. That is, the method works for any implementation of the ADT list. public static void displayList(ListInterface aList) { int numberOfEntries = aList.getLength(); System.out.println("The list contains " + numberOfEntries + " entries, as follows:"); for (int position = 1; position <= numberOfEntries; position++) System.out.println(aList.getEntry(position) + " is entry " + position); System.out.println(); } // end displayList Assuming the list runnerList from the example in Segment 4.12, the expression produces the following output: display- List(runnerList) The list contains 4 entries, as follows: 16 is entry 1 4 is entry 2 33 is entry 3 27 is entry 4 4.14 Example. A professor wants an alphabetical list of the names of the students who arrive for class today. As each student enters the room, the professor adds the student’s name to a list. It is up to the professor to place each name into its correct position in the list so that the names will be in alphabetical order. The ADT list does not choose the order of its entries. The following Java statements place the names Amy, Ellen, Bob, Drew, Aaron, and Carol in an alphabetical list. The comment at the end of each statement shows the list after the statement executes. // make an alphabetical list of the names // Amy, Ellen, Bob, Drew, Aaron, Carol ListInterface alphaList = new AList(); 90 CHAPTER 4 Lists alphaList.add(1, alphaList.add(2, alphaList.add(2, alphaList.add(3, alphaList.add(1, alphaList.add(4, "Amy"); "Ellen"); "Bob"); "Drew"); "Aaron"); "Carol"); // // // // // // Amy Amy Ellen Amy Bob Ellen Amy Bob Drew Ellen Aaron Amy Bob Drew Ellen Aaron Amy Bob Carol Drew Ellen After initially adding Amy to the beginning of the list and Ellen to the end of the list (at position 2), the professor inserts G G G G Bob between Amy and Ellen at position 2 Drew between Bob and Ellen at position 3 Aaron before Amy at position 1 Carol between Bob and Drew at position 4 This technique of inserting each name into a collection of alphabetized names is called an insertion sort. We will discuss this and other ways of ordering items in a later chapter. If we now remove the entry at position 4—Carol—by writing alphaList.remove(4); Drew and Ellen will then be at positions 4 and 5, respectively. Thus, alphaList.getEntry(4) would return a reference to Drew. Finally, suppose that we want to replace a name in this list. We cannot replace a name with just any name and expect that the list will remain in alphabetical order. Replacing Bob with Ben by writing alphaList.replace(3, "Ben"); would maintain alphabetical order, but replacing Bob with Nancy would not. The list’s alphabetical order resulted from our original decisions about where to add names to the list. The order did not come about automatically as a result of list operations. That is, the client, not the list, maintained the order. We could, however, design an ADT that maintains its data in alphabetical order. You will see an example of such an ADT in Chapter 13. Question 3 Suppose that alphaList contains a list of the four strings Amy, Ellen, Bob, and Drew. Write Java statements that swap Ellen and Bob and that then swap Ellen and Drew so that the list will be in alphabetical order. 4.15 Example. Let’s look at a list of objects that are not strings. Suppose that we have the class Name from Chapter 1 that represents a person’s first and last names. The following statements indicate how we could make a list of the names Amy Smith, Tina Drexel, and Robert Jones: // make a list of names as you think of them ListInterface nameList = new AList(); Name amy = new Name("Amy", "Smith"); nameList.add(amy); nameList.add(new Name("Tina", "Drexel"); nameList.add(new Name("Robert", "Jones"); Now let’s retrieve the name that is second in the list: Name secondName = (Name)nameList.getEntry(2); Notice that we must type-cast the object that getEntry returns. To accommodate entries of any class type, the list methods use Object as the type of entry. In particular, the return type of getEntry is Object. Thus, we must type-cast the returned entry to the data type of the entries in the list. That type is Name in this example. Java Class Library: The Interface List 91 Earlier we said that an ADT has data of the same type. As you will see in the next chapters, the implementations of the ADT list will not enforce this requirement. As this example just showed, you must know the data type of an entry in a list when you retrieve or remove it so that you can perform any necessary type cast. Although Java will let you place objects of various types in the same list, you would need to keep track of their data types. In general, requiring an ADT’s entries to have the same type makes life easier. Programming Tip: Type-cast returned objects ADT entries that a method returns are of type Object and must be type-cast to their actual type. Question 4 a. b. 4.16 The example in Segment 4.13 used getEntry to retrieve an entry from a list. Why was a type cast to String not necessary? Would a type cast to String be wrong? Example. Let’s talk a bit more about the previous example. The variable secondName is a reference to the second object of type Name in the list. Using this reference, we can modify the object. For example, we could change its last name by writing secondName.setLast("Doe"); If the class Name did not have set methods like setLast, we would be unable to modify the objects in this list. For instance, if we had a list of strings, we would not be able to alter one of the strings in this way. Once we create an object of the class String, we cannot alter it. We could, however, replace an entire object in the list—regardless of its type—by using the ADT list operation replace. A class, such as Name, that has set methods is a class of mutable objects. A class, such as String, without set methods is a class of immutable objects. Chapter 15 talks about such classes in more detail. Java Class Library: The Interface List 4.17 The standard package java.util contains an interface for the ADT list that is similar to our interface. Its name is List. The major difference between a list in the Java Class Library and our ADT list is the numbering of a list’s entries. A list in the Java Class Library uses the same numbering scheme as a Java array: The first entry is at position, or index, 0. In contrast, we begin our list at position 1. The interface List also declares more methods than our interface does. The following method signatures are for a selection of methods that are similar to the ones you have seen in this chapter. We have used blue to indicate where they differ from our methods. public public public public public public public public public boolean add(Object newEntry) void add(int index, Object newEntry) Object remove(int index) void clear() Object set(int index, Object anEntry) // like replace Object get(int index) // like getEntry boolean contains(Object anEntry) int size() // like getLength boolean isEmpty() The second add method is a void method. It throws an exception if index is out of range, instead of returning a boolean value, as our add method does. The method set is like our replace method, but 92 CHAPTER 4 Lists it returns a reference to the entry that was replaced in the list instead of returning a boolean value. The other differences are simply in the method names used. For example, the interface List uses get for our getEntry and size for our getLength. You can learn more about the interface List at http://java.sun.com/products/jdk/1.4/docs/api/index.html Using a List Is Like Using a Vending Machine 4.18 Figure 4-4 Imagine that you are in front of a vending machine, as Figure 4-4 depicts; better yet, take a break and go buy something from one! A vending machine I’m really thirsty—where is that vending machine? When you look at the front of a vending machine, you see its interface. By inserting coins and pressing buttons, you are able to make a purchase. Here are some observations that we can make about the vending machine: G G G G G You can perform only the specific tasks that the machine’s interface presents to you. You must understand these tasks—that is, you must know what to do to buy a soda. You cannot see or access the inside of the machine, because a steel shell encapsulates it. You can use the machine even though you do not know what happens inside. If someone replaced the machine’s inner mechanism with an improved version, leaving the interface unchanged, you could still use the machine in the same way. You, as the user of a vending machine, are like the client of the ADT list that you saw earlier in this chapter. The observations that we just made about the user of a vending machine are similar to the following observations about a list’s client: G The client can perform only the operations specific to the ADT list. These operations often are declared within a Java interface. Using a List Is Like Using a Vending Machine G G G G 4.19 C HAPTER S UMMARY 93 The client must adhere to the specifications of the operations that the ADT list provides. That is, the author of the client must understand how to use these operations. The client cannot access the data within the list without using an ADT operation. The principle of encapsulation hides the data within the ADT. The client can use the list, even though it cannot access the list’s entries directly—that is, even though the programmer does not know how the data is stored. If someone changed the implementation of the list’s operations, the client could still use the list in the same way, as long as the interface did not change. In the examples of the previous section, each list is an instance of a class that implements the ADT list. That is, each list is an object whose behaviors are the operations of the ADT list. You can think of each such object as the vending machine that we just described. Each object encapsulates the list’s data and operations just as the vending machine encapsulates its product (soda cans) and delivery system. Some ADT operations have inputs analogous to the coins you insert into a vending machine. Some ADT operations have outputs analogous to the change, soda cans, messages, and warning lights that a vending machine provides. Now imagine that you are the designer of the front, or interface, of the vending machine. What can the machine do, and what should a person do to use the machine? Will it help you or hinder you to think about how the soda cans will be stored and transported within the machine? We maintain that you should ignore these aspects and focus solely on how to use the machine—that is, on your design of the interface. Ignoring extraneous details makes your task easier and increases the quality of your design. Recall that abstraction as a design principle asks you to focus on what instead of how. When you design an ADT, and ultimately a class, you use data abstraction to focus on what you want to do with or to the data without worrying about how you will accomplish these tasks. We practiced data abstraction at the beginning of this chapter when we designed the ADT list. We referred to each entry in our list by its position within the list. As we chose the methods that a list would have, we did not consider how we would represent the list. Instead, we focused on what each method should do. Ultimately, we wrote a Java interface that specified the methods in detail. We were then able to write a client that used the list, again without knowledge of its implementation. If someone wrote the implementation for us, our program would presumably run correctly. If someone else gave us a better implementation, we could use it without changing our already-written client. This feature of the client is a major advantage of abstraction. G An abstract data type, or ADT, consists of both data and a set of operations on the data. An ADT provides a way to design a new data type independently of the choice of programming language. G A list is an ADT whose data consists of ordered entries. Each entry is identified by its position within the list. G A Java program manipulates or accesses a list’s entries by using only the operations defined for the ADT list. The manifestation of the ADT in a programming language encapsulates the data and operations. That is, the particular data representations and method implementations are hidden from the client. G When you use data abstraction to design an ADT, you focus on what you want to do with or to the data without worrying about how you will accomplish these tasks. That is, you ignore the details of how you represent data and how you manipulate it. 94 CHAPTER 4 Lists P ROGRAMMING T IPS After designing a draft of an ADT, confirm your understanding of the operations and their design by writing some pseudocode that uses the ADT. G After specifying an ADT and writing a Java interface for its operations, write some Java statements that use the ADT. In this way, you check both the suitability and your understanding of the specifications. An added benefit of doing this task carefully is that later you can use these same Java statements to test your implementation. G E XERCISES G ADT entries that a method returns are of type Object and must be type-cast to their actual type. 1. If myList is an empty list, what does it contain after the following statements execute? myList.add("alpha"); myList.add(1, "beta"); myList.add("gamma"); myList.add(2, "delta"); myList.add(4, "alpha"); myList.remove(2); myList.remove(2); myList.replace(3, "delta"); 2. Suppose that you want an operation for the ADT list that removes the first occurrence of a given object from the list. The signature of the method could be as follows: public boolean remove(Object anObject) Write comments that specify this method. 3. Write Java statements at the client level that return the position of a given object in the list myList. Assume that the object is in the list. 4. Suppose that you want an operation for the ADT list that returns the position of a given object in the list. The signature of the method could be as follows: public int getPosition(Object anObject) Write comments that specify this method. 5. Suppose that the ADT list did not have a method replace. Write Java statements at the client level that replace an object in the list nameList. The object’s position in the list is givenPosition and the replacement object is newObject. 6. Suppose that the ADT list did not have a method contains. Suppose further that nameList is a list of Name objects, where Name is as defined in Chapter 1. Write Java statements at the client level that determine whether the Name object myName is in the list nameList. 7. Suppose that you have a list that is created by the following statement: ListInterface studentList = new AList(); Imagine that someone has added to the list several instances of the class Student that Chapter 2 defined. a. Write Java statements that display the last names of the students in the list in the same order in which the students appear in the list. Do not alter the list. b. Write Java statements that interchange the first and last students in the list. Using a List Is Like Using a Vending Machine 95 8. Consider a class Coin that represents a coin. The class has methods such as getValue, toss, and isHeads. The method getValue returns the value, or denomination, of a coin. The method toss simulates a coin toss in which the coin lands either heads up or tails up. The method isHeads returns true if a coin is heads up. Suppose that coinList is an ADT list of coins that have randomly selected denominations. Toss each of these coins. If the result of a coin toss is heads, move the coin to a second list called headsList; if it is tails, leave the coin in the original list. When you are finished tossing coins, compute the total value of the coins that came up heads. Assume that the list headsList has been created for you and is empty initially. P ROJECTS 1. The introduction to this book spoke of a bag as a way to organize data. A grocery bag, for example, contains items in no particular order. Some of them might be duplicate items. The ADT bag, like the grocery bag, is perhaps the simplest of data organizations. It holds objects but does not arrange or organize them further. Design an ADT bag. Many operations are analogous to those of the ADT list, but the entries do not have positions. In addition to these basic operations, include the following: G G G A union operation that combines the contents of two bags into a third bag An intersection operation that creates a bag of those items that occur in both of two bags A difference operation that creates a bag of the items that would be left in one bag after removing those that also occur in another bag Specify each ADT operation by stating its purpose, by describing its parameters, and by writing preconditions, postconditions, and a pseudocode version of its signature. Then write a Java interface for the ADT bag that includes javadoc-style comments. 2. You might have a piggy bank or some other receptacle to hold your spare coins. The piggy bank holds the coins but gives them no other organization. And certainly the bank can contain duplicate coins. The piggy bank is like the ADT bag that you designed in Project 1, but it is simpler. It has only three operations: You can add a coin to the bank, remove one (you shake the bank, so you have no control over what coin falls out), or determine whether the bank is empty. Design the ADT piggy bank, assuming that you have the ADT bag from Project 1 and the class Coin from Exercise 8. Write a Java interface for the ADT piggy bank that includes javadoc-style comments. 3. Santa Claus allegedly keeps lists of those who are naughty and those who are nice. On the naughty list are the names of those who will get coal in their stockings. On the nice list are those who will receive gifts. Each object in this list contains a name (an instance of Name, as defined in Chapter 1) and a list of that person’s gifts (an instance of an ADT list). Design an ADT for the objects in the nice list. What operations should this ADT have? After you design the ADT, implement it by writing a Java class. Assume that you have an implementation of the ADT list—that is, assume that the class AList implements ListInterface, as given in this chapter. Finally, create some instances of your class and place them on Santa’s nice list. 96 CHAPTER 4 Lists 4. A recipe contains a title, a list of ingredients, and a list of directions. An entry in the list of ingredients contains an amount, a unit, and a description. For example, 2 cups of flour could be an entry in this list. Implement a class of recipes, assuming that the class AList implements ListInterface, as given in this chapter. The amount of an ingredient can be a double value or an instance of the class MixedNumber, which was described in Project 3 of Chapter 3. ...
View Full Document

This note was uploaded on 04/29/2010 for the course CS 5503 taught by Professor Kaylor during the Spring '10 term at W. Alabama.

Ask a homework question - tutors are online