• No results found

Implementations

4

Contents

4.1 Preliminaries 134

4.1.1 The Class Node 136

4.2 A Link-Based Implementation of the ADT Bag 137

4.2.1 The Header File 138

4.2.2 Defi ning the Core Methods 139 4.2.3 Implementing More Methods 143

4.3 Using Recursion in Link-Based Implementations 148

4.3.1 Recursive Defi nitions of Methods in LinkedBag 148

4.4 Testing Multiple ADT Implementations 150

4.5 Comparing Array-Based and Link-Based Implementations 153

Summary 154 Exercises 155

Programming Problems 156

Prerequisites

Chapter 1 Data Abstraction: The Walls C++ Interlude 1 C++ Classes

Chapter 2 Recursion: The Mirrors (for Section 4.3 )

Chapter 3 Array-Based Implementations (incidental dependence) C++ Interlude 2 C++ Pointers, Polymorphism, and Memory Allocation

T

his chapter introduces you to a link-based data structure using C++ pointers, which were described in C++ Interlude 2. You will learn how to work with such structures and how to use one to implement a class of bags. The material in this chapter is essential to much of the presentation in the chapters that follow.

4.1

Preliminaries

Let’s consider components that can be linked to one another. Each component—usually called a

node —contains both a data item and a “pointer” to the next item. Because each node must contain

two pieces of information—the data item and a pointer to the next node—it is natural to conclude that each node should be an object. One member of the object is the data item and the other is a pointer. Typically, such pointers are C++ pointer variables.

FIGURE 4-1 A node

item next

"ab"

FIGURE 4-2 Several nodes linked together

"ab" "cd" "ef" "gh" "ij" item next

item next

item next item next item next

nullptr

1 An alternative notation, (*nodePtr).getItem() , is possible, but this book will not use it. Although this notation is analogous to the use of the dot operator to reference the members of a named structure, the -> operator is more suggestive of pointers.

Figure 4-1 illustrates a single node, and Figure 4-2 shows several nodes linked together. Here, the data portion of each node contains a string. We use arrows to represent the pointers, but what type of pointer should you use within a node, and to what will it point? You might guess that the pointer should point to a string, but actually it must point to a node that contains the string. Because pointers can point to any data type except fi les—and since nodes are objects—pointers can, in fact, point to nodes. Thus, a node of type Node , for example, will have as one of its members a pointer to another node of typeNode . For example, the statement

Node<string>* nodePtr;

defi nes a pointer variable nodePtr that can point to a node of type Node that contains a string as its data item. Nodes should be dynamically allocated. For example,

nodePtr = new Node<string>();

allocates a node to which nodePtr points. To access the members of a node, you will need the -> notation introduced in C++ Interlude 2, because the node does not have a user-defi ned name. Suppose our class of nodes has an accessor method, getItem , that returns the value of the data member item . To reference item in the node to which nodePtr points, you write nodePtr->getItem() .1 Likewise,

if our class of nodes has the methodgetNext to access the data member next , the expression nodePtr ->getNext() represents the pointer next . For example, if nodePtr points to the second node in Figure 4-2 , Defi ning a pointer to

a node Dynamically allocating a node Referencing a node member VideoNote Linked chain concepts

Preliminaries 135

nodePtr->getItem() returns the string "cd" and nodePtr->getNext() returns a pointer to the third node. We can save this new pointer in nodePtr itself by writing

nodePtr = nodePtr->getNext();

If we execute the previous statement again, nodePtr will point to the fourth node in Figure 4-2 . Executing the statement one more time makes nodePtr point to the last node shown in Figure 4-2 . What is the value of the member next in this last node? That is, what value does nodePtr->getNext() return? We want this value to be a signal that we have reached the last of the linked nodes. If this value is nullptr , we easily can detect when we have reached the end of the linked nodes.

We have one more detail to consider: Nothing so far points to the fi rst node. If you cannot get to the fi rst node, you cannot get to the second node; and if you cannot get to the second node, you cannot get to the third node; and so on. The solution is to have an additional pointer whose sole purpose is to point to the fi rst of several linked nodes. Such a pointer is called the head pointer or simply the head of the data structure.

Figure 4-3 illustrates a linked chain of nodes with a head pointer. Observe that the head pointer headPtr is different from the other pointers in the diagram in that it is not within one of the nodes. The variable headPtr simply enables you to access the chain’s beginning. What value should headPtr contain if there are no nodes for it to point to? Assigning headPtr the value nullptr is a logical choice in this case.

The head pointer points to the fi rst node

If headPtr is nullptr, it points to nothing

FIGURE 4-3 A head pointer to the fi rst of several linked nodes

"ab" "cd" "ef" "gh" "ij" headPtr item next item next item next item next item next

nullptr

Note:

Although all of the pointers shown in Figure 4-3 point to nodes, the head pointer is a simple pointer variable, whereas the next members are within nodes.

Programming Tip:

It is a common mistake to think that before you can assign headPtr a value, you fi rst must create a new Node object. This misconception is rooted in the belief that the variable headPtr does not exist if it does not point to a node. This is not at all true; headPtr is a pointer variable waiting to be assigned a value. Thus, for exam- ple, you can assign nullptr to headPtr without fi rst using new . In fact, the sequence

headPtr =new Node; // An incorrect use of new headPtr =nullptr;

destroys the content of the only pointer— headPtr —to the newly created node, as Figure 4-4 illustrates. Thus, you have needlessly created a new node and then made it inaccessible. This action creates a memory leak in your program and should be avoided!