• No se han encontrado resultados

5.2 C ONTRASTACIÓN DE HIPÓTESIS

5.2.2 Hipótesis secundarias

Just as we did when we defi ned an array-based implementation of the ADT bag in Chapter 3 , we begin our new implementation by defi ning the same core methods: the constructor, add , toVector , getCurrentSize , and isEmpty . We will write stubs for the remaining methods, including the copy constructor and destructor.

The constructor. The following default constructor initializes the head pointer and the current

number of items in the bag: template< class ItemType>

LinkedBag<ItemType>::LinkedBag() : headPtr( nullptr), itemCount(0) {

} // end default constructor

The method add. A bag does not order its entries, so the method add can insert a new item at any convenient location within the linked chain of nodes that contains the bag’s entries. The most conven- ient place for us to make this insertion is at the beginning of the chain, because the fi rst node is the only one that we can access directly. Figure 4-6 illustrates how we add a new node to the beginning of an existing chain of nodes.

You must make headPtr point to the new node, and the new node must point to the node that had been at the beginning of the chain. Note how the following defi nition accomplishes this:

template< class ItemType>

bool LinkedBag<ItemType>::add( const ItemType& newEntry) {

// Add to beginning of chain: new node references rest of chain; {

private:

Node<ItemType>* headPtr; // Pointer to first node

int itemCount; // Current count of bag items

// Returns either a pointer to the node containing a given entry // or the null pointer if the entry is not in the bag.

Node<ItemType>* getPointerTo( const ItemType& target) const; public:

LinkedBag();

LinkedBag( const LinkedBag<ItemType>& aBag); // Copy constructor

virtual ~LinkedBag(); // Destructor should be virtual

int getCurrentSize() const; bool isEmpty() const;

bool add( const ItemType& newEntry); bool remove( const ItemType& anEntry); void clear();

bool contains( const ItemType& anEntry)const; int getFrequencyOf( const ItemType& anEntry)const; vector<ItemType> toVector() const;

}; // end LinkedBag #include "LinkedBag.cpp" #endif

// (headPtr is nullptr if chain is empty)

Node<ItemType>* newNodePtr = new Node<ItemType>(); newNodePtr->setItem(newEntry);

newNodePtr->setNext(headPtr); // New node points to chain headPtr = newNodePtr; // New node is now first node itemCount++;

return true; } // end add

FIGURE 4-6 Inserting at the beginning of a linked chain

newNodePtr

headPtr "ab" "cd" "ij"

"nn"

Observe that if the bag is empty before the insertion headPtr is nullptr , so the next pointer of the new node is set to nullptr . This step is correct because the new item is the last item—as well as the fi rst item—in the chain.

Insertion into an empty chain is really an insertion at the beginning of the chain Inserting a node at the beginning of a linked chain

Programming Tip:

Our method add uses the operator new to create a new node object and place it on the heap. Because C++ does not have garbage collection as Java does, it is our class’s responsibility to ensure that the object is removed from the heap usingdelete . As discussed in the second C++ Interlude, the class destructor is one method where we do this. Since we created this node to store an item we are adding to the bag, it follows that another opportunity to delete the node is when we remove the item from the bag.

Question 1

Consider a linked chain of three nodes, such that each node contains a string. The fi rst node contains "A" , the second node contains "B" , and the third node contains "C" .

a. Write C++ statements that create the described linked chain. Beginning with a head

pointerheadPtr that contains nullptr , create and attach a node for "C" , then create and attach a node for"B" , and fi nally create and attach a node for "A" .

b. Repeat part a , but instead create and attach nodes in the order "A" , "B" , "C" .

CHECK POINT

The method toVector. Recall that the method toVector retrieves the entries that are in a bag and returns them to the client within a vector. A loop within toVector adds the bag’s entries to this vector. In the array-based implementation, this loop simply accesses an array of these entries. Here we must retrieve the entries from the nodes in a chain. To do that, we must move from node to node; that is, we must traverse the chain. As we visit each node, we copy its data item into the vector.

A traverse operation visits each node in the linked chain

A Link-Based Implementation of the ADT Bag 141

Let’s write some high-level pseudocode for this loop, given the linked chain pictured in Figure 4-5 .

Let a current pointer point to the first node in the chain

while ( the current pointer is not the null pointer ) {

Assign the data portion of the current node to the next element in a vector

Set the current pointer to the next pointer of the current node

}

This solution requires that you keep track of the current position within the chain. Thus, you need a pointer variable—let’s call it curPtr —that points to the current node.

Note:

The pointer variable curPtr is analogous to the integer variable curIndex that we used in Section 3.2.4 of Chapter 3 to keep track of the current entry in an array.

Initially, curPtr must point to the fi rst node. Because headPtr points to the fi rst node, simply copy headPtr into curPtr by writing

Node<ItemType>* curPtr = headPtr;

Then you can use the expression curPtr->getItem() to access the data portion of the current node. After copying the data into the vector, you advance the current pointer to the next node by writing

curPtr = curPtr->getNext();

Figure 4-7 illustrates this action. If the previous assignment statement is not clear, consider Node<ItemType>* temp = curPtr->getNext();

curPtr = temp;

and then convince yourself that the intermediate variable temp is not necessary.

FIGURE 4-7 The effect of the assignment curPtr = curPtr->getNext()

curPtr

Before

curPtr After "cd" "ef" "cd" "ef"

These ideas lead to the following defi nition of toVector : template< class ItemType>

vector<ItemType> LinkedBag<ItemType>::toVector() const {

vector<ItemType> bagContents; Node<ItemType>* curPtr = headPtr;

int counter = 0;

{ bagContents.push_back(curPtr->getItem()); curPtr = curPtr->getNext(); counter++; } // end while return bagContents; } // end toVector

Here curPtr points to each node in a nonempty chain during the course of the loop’s execution, and so the data portion of each node is accessed and assigned to the end of the vector. After the last node is accessed, curPtr becomes nullptr , and the loop terminates. When the bag is empty—that is, when headPtr is nullptr —the loop is correctly skipped. Note that the variable counter , while not neces- sary, provides a defense against going beyond the end of the chain.

Programming Tip:

A common error in the while statement we used in toVector is to comparecurPtr->getNext() instead of curPtr with nullptr . When curPtr points to the last node of a nonempty chain,curPtr->getNext() is nullptr , and so the loop would terminate before accessing the data in the last node. In addition, when the chain is empty, headPtr —and therefore— curPtr are nullptr , making the value of curPtr->getNext() undefi ned. Such references are incorrect and should be avoided.

The methods isEmpty and getCurrentSize. The last two methods in our core group have the fol-

lowing defi nitions, which are like the ones in the array-based implementation given in the previous chapter.

template< class ItemType>

bool LinkedBag<ItemType>::isEmpty() const {

return itemCount== 0; } // end isEmpty

template< class ItemType>

int LinkedBag<ItemType>::getCurrentSize() const {

return itemCount; } // end getCurrentSize

Note:

Testing the core methods

Just as we did in the previous chapter, you should test each method as you defi ne it. In fact, with little change, you can revise the program given in Listing 3-2 and use it to test the core methods that we have just defi ned. The bag in that program became full, but it will not here. In Section 4.4 , we will examine how to change that program so that it can test multiple bag implementations.

Question 2

Why are only a few changes necessary to reuse the code in Listing 3-2? How would you implement the changes using the “fi nd and replace” functionality of a text editor or IDE?

CHECK POINT

A Link-Based Implementation of the ADT Bag 143