Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 43

Chapter XXXIX

Linked Lists I

Chapter XXXIX Topics


39.1 Introduction

39.2 Creating a Stack with a Linked List

39.3 Using the NULL Pointer

39.4 Creating a Queue with a Linked List

39.5 Creating an Ordered Linked List

39.6 Deleting from an Ordered Linked List

39.7 Considering all Possible Cases

39.8 Linked Lists and Memory Locations

39.9 Practice Exercises

Chapter XXXIX Linked Lists 39.1


39.1 Introduction

Your textbook, Part IV, is titled Abstract Data Structures. Now abstract is nice
and provides many benefits for program design. On the other hand, there comes
the implementation reality check. Sooner or later you need to sit down and start
to put some code on paper, in the computer or somewhere. This chapter is the
first of several chapters that is all about the reality of implementation linked lists.

In the last chapter, you were introduced to the concept of the linked list. You
learned how linked lists are an improvement over lists that requires contiguous
blocks of memory. You saw how linking nodes can be very efficient both in the
area of execution speed and memory allocation.

You also did an assignment that graphically drew some linked lists. Do get used
to something right now. Linked lists can be tricky critters and it is wise to have a
notepad nearby, to draw proctors, when you work with linked lists to insure that
you do not get confused about the organization of the data structure.

It will take two chapters to introduce all the various ways that linked lists can be
implemented. Fundamentally, the concepts are the same. Data needs to be stored
in some data structure. Along with the stored data there is also information that
links the record to some other record located elsewhere in memory. The
allocation of this memory occurs during program execution whenever there is a
need to store additional data.

39.2 Creating a Stack with a Linked List

You may be surprised that this section talks about stacks. After all, are we not
working with linked lists? We certainly are doing linked lists and this section
will explain how to implement the data structure that allows the efficient linking
of nodes. In this first section we will not be concerned with complexities of
inserting and deleting nodes in the middle of a list. Right now the simplest way
to learn about handling links is to concentrate on linking at one end of a linked
list. The end result of building a list at one end only is that the list behaves like a
stack. However, the motivation is to learn the easiest type of linked list
implementation, and this just happens to be a stack. In the previous chapter you
learned how to draw pictures that created a linked list both as a stack and a queue.

39.2 Exposure C++, Part IV, Abstract Data Types 12-08-99


The finer distinction between what exactly is a stack and what is a linked list will
come later. Right now consider that you are working with a linked list because
linking is used to connect separate nodes that store data. At the same time these
nodes are linked in a LIFO sequence, which makes the list behave like a stack.

The secret of implementing a linked list revolves around a rather peculiar looking
data structure. The struct data structure is a good choice since it allows different
data types. Each node in a linked list needs to store data as well as information
about the next node. A good choice for this “link” is the use of a pointer, which
stores the address of the next node in the list. You have learned that a pointer is
not simply an address, but an address of a memory cell that has the required
number of bytes of the particular type being used. An integer pointer has 2-byte
memory cells, a float pointer has 4-byte memory cells, and a pointer to a data
structure will have the number of bytes required for the entire data structure.

This brings up a curious problem. Each node in the linked list will then contain a
field, which is a pointer to another node. But the pointer is inside the very
structure that it points to. The solution is to use a self-referencing declaration like
the one shown below.

// self-referenced declaration

struct ListNode
{
char Data;
ListNode* Next;
};

ListNode is a data structure with two fields. The first field, Data, is a character
to store necessary information. This field can be any data type, including some
other data structure. The second field, Next, is a pointer and notice that this is a
pointer to ListNode. Normally, it is not possible to make a reference to anything
that is not yet completely declared. This is allowed, in the case of making
reference to some memory location that will be allocated during program
execution.

Self-Referenced Data Structure

Chapter XXXIX Linked Lists 39.3


A linked list data structure is made up of self-referential
objects, called nodes. If the node is of ListNode type then
one - or more - fields is a pointer that references ListNode
like the Next field in the example below.

struct ListNode
{
char Data;
ListNode* Next;
};

This is the type of stuff that often causes major confusion. The only reason why
this self-referential stuff is included is for multiple reading purposes. After you
look at a variety of program examples that use this type of structure, you will see
a pattern that will help to explain what is going on. A second or third time passed
over this page will be a whole lot more agreeable than it is the first time.

It is also important to realize that ListNode, Data, and Next are not special C++
keywords at all. The exact same functionality can be achieved with the following
node declaration.

// functionally the same as ListNode

struct Tiger
{
char Book;
Tiger* Giraffe;
};

The first linked list program example will create a small linked list with only two
nodes. Only characters are stored as data in the linked list besides the linking
information. Graphically, the linked list has the following appearance:

39.4 Exposure C++, Part IV, Abstract Data Types 12-08-99


[P] Y X

The diagonal line in the picture indicates the NULL pointer or address. It is used
to indicate the end of the list. NULL is a pointer, but it does not point to any
other node. Its only purpose in life is to help identify the end of a list. The value
of NULL is zero (0). Program PROG3901.CPP shows the syntax of this first
program. Every program statement in this example will be explained in detail on
the next page.

// PROG3901.CPP
// This program creates a linked list with two nodes.

#include <iostream.h>
#include <conio.h>

struct ListNode
{
char Data;
ListNode *Next;
};

void main()
{
clrscr();
ListNode *P; // define pointer P
ListNode *Temp; // define temporary pointer Temp
Temp = NULL; // [1]
P = new ListNode; // [2]
P->Data = 'X'; // [3]
P->Next = Temp; // [4]
Temp = P; // [5]
P = new ListNode; // [6]
P->Data = 'Y'; // [7]
P->Next = Temp; // [8]
Temp = P; // [9]
cout << "LIST WITH TWO NODES IS COMPLETE" << endl;
getch();
}

PROG3901.CPP OUTPUT

LIST WITH TWO NODES IS COMPLETE

Chapter XXXIX Linked Lists 39.5


You will not need to go back to the program listing to compare the line numbers
with the explanations. Each line will be reprinted , as it is explained. Make sure
that you read very slowly. Look at the explanations carefully, and look at any of
the pictures that symbolically depict the linked list being created. You will need
to get in the habit of drawing pictures yourself. The program syntax of pointer
programs is pretty obscure and lacks the readability that you have grown
accustomed to in previous C++ programs. Take time. It will be a while before
this pointer business will be a comfortable subject. Remember when you were
first introduced to parameters. That seemed pretty strange then and now
parameters are something that you take for granted. Have faith, this topic will
become simpler too, with time and effort.

[1] Temp = NULL;


One of the two pointer variables, called Temp, is assigned to point at
NULL. NULL is a zero address. It indicates the end of a linked list.

[2] P = new ListNode;


The new operator finds available memory and creates a pointer that stores
the memory address of the new node.

[3] P->Data = 'X';


P->Data is the field that contains the data, which in this case is a
character. This statement stores character X in the Data filed.

[4] P->Next = Temp;


P->Next is an unusual field because Next is both a pointee and a pointer.
This field stores the address of the next node in the linked list. In this
statement Next becomes Temp, which means that Next will equal NULL.

[5] Temp = P;
P is patiently pointing at the newly created object. Temp is tired of
pointing at NULL, and now points to the same object as P. P->Next is
left, and doomed for now to point at NULL.

[6] P = new ListNode;


P says good-bye to Temp and jumps into action. A brand-new “empty”
pointer object is created and P is there to point at it.

[7] P->Data = 'Y';


The character Y is assigned to the field P->Data.

[8] P->Next = Temp;


The pointer P->Next is assigned to the value of Temp. But Temp is
pointing at the first pointer object. Since P->Next points where Temp is
pointing, this results in “linking” the two nodes.
[9] Temp = P;

39.6 Exposure C++, Part IV, Abstract Data Types 12-08-99


Temp moves up to P, to allow additional linking.

The next program example creates the exact same linked list of two nodes. The
reason for the second look is to see the memory address stored by the pointers at
different parts in the program. In particular, it shows how the Next pointer stores
the same address as the P pointer after the nodes are linked together.

// PROG3902.CPP
// This program creates a linked list with two nodes and
// investigates the contents at different memory locations.

#include <iostream.h>
#include <conio.h>

struct ListNode
{
char Data;
ListNode *Next;
};

void main()
{
ListNode *P;
ListNode *Temp;
clrscr();
Temp = NULL; cout << "Temp = " << Temp << endl;
cout << endl;
P = new ListNode; cout << "P = " << P << endl;
P->Data = 'X'; cout << "P->Data = " << P->Data << endl;
P->Next = Temp; cout << "P->Next = " << P->Next << endl;
Temp = P; cout << "Temp = " << Temp << endl;
cout << endl;
P = new ListNode; cout << "P = " << P << endl;
P->Data = 'Y'; cout << "P->Data = " << P->Data << endl;
P->Next = Temp; cout << "P->Next = " << P->Next << endl;
Temp = P; cout << "Temp = " << Temp << endl;
getch();
}

PROG3902.CPP OUTPUT

Temp = 0x0

P = 0x90eb0004
P->Data = X
P->Next = 0x0
Temp = 0x90eb0004

P = 0x90ec0004
P->Data = Y

Chapter XXXIX Linked Lists 39.7


P->Next = 0x90eb0004
Temp = 0x90ec0004

39.3 Using the NULL Pointer

Program PROG3903.CPP will demonstrate how handy the NULL pointer is.
This program creates a linked list with three nodes in the same manner as the
previous two programs with one extra node added. The new feature is showing
how the linked list is traversed so that each node can be visited when the list is
completed. You and I both know that the list only has three nodes and it would
be simple to use a for loop that repeats three times. It is better to see how a
linked list should be traversed without concern about the number of nodes in the
list. The handy NULL pointer functions as a sentinel to alert the repetition
process to halt. This allows the use of a conditional loop to traverse every node
in the list, regardless of the number of current nodes.

The Null Pointer

C++ provides a special pointer with a zero-value address.


This pointer is called the NULL pointer.

Programs work correctly when 0 is assigned to a pointer,


but the use of the NULL constant provides better readability.

The NULL pointer can be dereferenced like other pointers


with statements like NULL->Data or (*NULL).Data.

Dereferencing the NULL pointer can have very serious


program consequences to proper program execution. Do
not expect the C++ compiler to catch dereference mistakes.

Dereferencing the NULL pointer problems will be explained


in greater detail in the next chapter.

The output execution of the next program should demonstrate that this linked list
has some serious family ties to the stack data structure. The characters X, Y, and
Z are assigned to the nodes in the list and traversing the list displays these three
characters in reverse order.

39.8 Exposure C++, Part IV, Abstract Data Types 12-08-99


// PROG3903.CPP
// This program creates a linked list with three nodes and
// displays the data in the linked list.
// The list behaves like a stack data structure.

#include <iostream.h>
#include <conio.h>

struct ListNode
{
char Data;
ListNode *Next;
};

void main()
{
clrscr();
ListNode *P;
ListNode *Temp;
Temp = NULL;
P = new ListNode;
P->Data = 'X';
cout << "Storing P->Data: " << P->Data << endl;
P->Next = Temp;
Temp = P;
P = new ListNode;
P->Data = 'Y';
cout << "Storing P->Data: " << P->Data << endl;
P->Next = Temp;
Temp = P;
P = new ListNode;
P->Data = 'Z';
cout << "Storing P->Data: " << P->Data << endl;
P->Next = Temp;
Temp = P;
cout << endl;
while (P != NULL)
{
cout << "Visiting P->Data: " << P->Data << endl;
P = P->Next;
}
cout << endl;
getch();
}

PROG3903.CPP OUTPUT

Storing P->Data: X
Storing P->Data: Y
Storing P->Data: Z

Chapter XXXIX Linked Lists 39.9


Visiting P->Data: Z
Visiting P->Data: Y
Visiting P->Data: X

All the previous linked list programs have rather inefficiently created nodes in a
linked list with program code for each node. This was inefficient but it was
readable and made it easier to understand the relationship between the different
nodes in the linked list. In the next program a linked list of twenty-six nodes will
store every character in the alphabet. Pay particular attention to the statement
Temp = NULL; That statement is not placed inside the loop. Hopefully you
realize that this statement only makes sense at the very first creation of the linked
list. The very first node in the list has its Next pointer equal to NULL. All
succeeding Next pointers connect to a node in the list. If you were not convinced
before that this linked list behaves like a stack, you should believe it with this
example. Twenty-size letters displayed in reverse order provides ample evidence.

// PROG3904.CPP
// This program creates a linked list with 26 nodes and displays
// the data stored in the linked list.
// The linked list is created as a stack data structure.

#include <iostream.h>
#include <conio.h>

struct ListNode
{
char Data;
ListNode *Next;
};

void main()
{
clrscr();
ListNode *P;
ListNode *Temp;
int K;

Temp = NULL;

for (K = 65; K <= 90; K++)


{
P = new ListNode;
P->Data = (char) K;
cout << P->Data << " ";
P->Next = Temp;
Temp = P;
}

cout << endl << endl;


while (P != NULL)
{

39.10 Exposure C++, Part IV, Abstract Data Types 12-08-99


cout << P->Data << " ";
P = P->Next;
}
cout << endl;
getch();
}

PROG3904.CPP OUTPUT

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

Z Y X W V U T S R Q P O N M L K J I H G F E D C B A

So think about this little question. We have a data structure here that we call a
linked list, and this linked list behaves in every way like a stack. So is this data
structure a stack or is the data structure a linked list? Think about it.

39.4 Creating a Queue with a Linked List

Perhaps you are still busily pondering over the is-it-a-stack-or-is-it-a-linked-list


question. It may help to add some additional information. How about making a
few strategic changes in the construction of our linked list and change it such that
it behaves like a queue. Just in case you have forgotten a stack behaves like a
LIFO and a queue behaves like a FIFO. A LIFO is a data structure that is
accessed Last In, First Out. A FIFO is a data structure that is accessed First In,
First Out. You have seen in previous chapters that we could use the same record
to create a stack or a queue. It makes sense that we can pull some similar tricks
with the linked list and use it for various purposes as well.

Program PROG3905.CPP once again creates a linked list of three nodes. Take a
quick look at the program first on the next page, and the output execution. The
output will probably satisfy you that the program appears to be inclined toward
the queue direction. Why is it now a queue? Maybe these pictures will help.

X Y Z [P] (stack)

Chapter XXXIX Linked Lists 39.11


(queue) [P] X Y Z

The pictures are intentionally drawn so that it appears that the list grows from left
to right. Symbolically speaking, that is correct if you consider that the nodes in
both lists are created starting with the X node and ending with the Z node. In the
case of the stack, the latest or current node that is created, points its Next pointer
to the previous node that was created. Each new node in the stack-type linked list
grows further and further away from the node with the NULL pointer.

The queue-type linked list is a different story. Each new node that is created
assigns NULL to its Next pointer. It seems that the latest node created is
constantly treated like the last node in the list. Furthermore, it is the previous
node that is linked to the current node. The Next pointers are opposite in their
linking scheme. This is precisely what makes one program behave like a stack
and the other program behave like a queue.

// PROG3905.CPP
// This program creates a linked list with three nodes and
// displays the data stored in the linked list.
// The linked list is created as a queue data structure.

#include <iostream.h>
#include <conio.h>

struct ListNode
{
char Data;
ListNode *Next;
};

void main()
{
clrscr();
ListNode *P;
ListNode *Temp;
ListNode *Front;

Front = new ListNode;


Front->Data = 'X';
cout << "Front->Data: " << Front->Data << endl;
Front->Next = NULL;
Temp = Front;

P = new ListNode;
P->Data = 'Y';
cout << "P->Data: " << P->Data << endl;

39.12 Exposure C++, Part IV, Abstract Data Types 12-08-99


P->Next = NULL;
Temp->Next = P;
Temp = P;

P = new ListNode;
P->Data = 'Z';
cout << "P->Data: " << P->Data << endl;
P->Next = NULL;
Temp->Next = P;
Temp = P;

cout << endl;


P = Front;
while (P != NULL)
{
cout << "P->Data: " << P->Data << endl;
P = P->Next;
}

cout << endl;


getch();
}

PROG3905.CPP OUTPUT

Front->Data: X
P->Data: Y
P->Data: Z

P->Data: Z
P->Data: Y
P->Data: X

Do you understand why there is an extra pointer used, called Front? The earlier
group of programs seemed to work fine with only two pointers and now there are
three. First of all, you need to realize that it takes two pointers to build any type
of a linked list. One pointer needs to point to each of the two nodes that will be
linked together. The stack data structure implemented with a linked list means
that the “top” of the stack is at the same place as the end of the linked list where
new nodes will be added in the future.

The story is different with a queue. New queue elements are added to the back of
the linked list. This explains why each new node is assigned NULL to its Next
pointer field. The queue builds steadily away from the first node where the list
was started. However, it is the first node that must be accessed when the queue is
traversed.

Chapter XXXIX Linked Lists 39.13


Remember that you are dealing with a FIFO and some pointer needs to keep
track of that very first node that was created. Without the Front pointer it would
not be possible to access any node in the list except the very last node.

Next Pointer Rule

The Next pointer or linking pointer by any other name is


one-directional. This linking pointer is only capable of
pointing to another node.

In other words, if Node A points to node B, the two nodes


are linked but it is not possible to traverse from node B
back to node A with the link A B.

The importance of the Front pointer is reinforced with the next program. Once
again a loop is used to create a linked list with twenty-six nodes. You will note in
this program that a complete node is created before the loop is started. This very
first node is recorded with the Front pointer and then the loop may start to build
the list for the next twenty-five nodes. This time the alphabet is displayed in the
same order as it was constructed. We are definitely talking queue here.

So are you any closer to the question of what is it? Are these data structures
stacks, or queues or linked lists or everything at the same time? What is going on
here? Keep thinking and remember that the best students do not have the best
answers, they have the best questions.

// PROG3906.CPP
// This program creates a linked list with 26 nodes and displays
// the data stored in the linked list.
// The linked list is created as a queue data structure.

#include <iostream.h>
#include <conio.h>

struct ListNode
{

39.14 Exposure C++, Part IV, Abstract Data Types 12-08-99


char Data;
ListNode *Next;
};

void main()
{
clrscr();
ListNode *Front;
ListNode *P;
ListNode *Temp;
int K;

Front = new ListNode;


Front->Data = (char) 65;
cout << Front->Data << " ";
Front->Next = NULL;
Temp = Front;

for (K = 66; K <= 90; K++)


{
P = new ListNode;
P->Data = (char) K;
cout << P->Data << " ";
P->Next = NULL;
Temp->Next = P;
Temp = P;
}

cout << endl << endl;


P = Front;
while (P != NULL)
{
cout << P->Data << " ";
P = P->Next;
}

cout << endl;


getch();
}

PROG3906.CPP OUTPUT

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

Chapter XXXIX Linked Lists 39.15


39.5 Creating an Ordered Linked List

You have some serious recollection that linked lists would solve the linear list
problem of shifting elements during insertion and deletion processes. So far none
of this has been addressed. The two previous linked list structures have behaved
like a stack and a queue and that basically means that all access has been at one
end of the list. There has not been any need to insert a node somewhere in the
middle of the list. This should be odd because that was one of the big
motivations of working with link lists.

The reason for starting with a stack and a queue was to take small bites at a time
of this linked list stuff. The stack is the easiest linked list to build and the queue a
little bit more complicated. Now you are ready to treat a linked list properly and
make sure that the list is ordered in the manner of a linear list. The list should be
created such that the data is sorted by some pre-determined method.

The next program example starts by filling an array with a random set of
numbers. This array is then passed to another function in charge of creating an
ordered linked list. The process - logically speaking - is completely identical to
the insertion sort that you learned long ago. You need to find the proper location
for the new number and insert the number at that location in the list. This process
is simpler to implement with an indexed list because every element in the array
can be accessed with its index. Sorting with an array becomes a manipulation and
shifting process based on the index values of adjacent list elements.

The same process with a linked list is more efficient but also more complex. It is
not sufficient to identify the insert or delete location. A single pointer at a desired
location is not capable of handling the insertion process.

Consider the following diagram. An ordered linked list exists with data ordered
alphabetically. A new node needs to be inserted with data K.

[P] K

[F] A G M T

In this situation node K needs to be inserted between nodes G and M. The


approach we will use is to traverse the list with two temporary pointers such that
one pointer is at G, and the other pointer is at M. This stage is shown below and
makes the insertion process easy.

[P]

39.16 Exposure C++, Part IV, Abstract Data Types 12-08-99


K

[F] A G M T

[T1] [T2]

Provided we have pointers positioned, as shown above, the linking of the new
node can be accomplished with the following two statements:

T1->Next = P;
P->Next = T2;

After these two statements are executed the linked list takes on the following
appearance. Node K is now inserted into the correct location.

A G M T

A G K M T

Program PROG3907.CPP is quite long. However, the focus of the ordered


linked list is not quite so bad. Function CreateList exists to create an array of
random integers and displays each random integer as it is assigned to the array.
This array will be used in function SortList to create an ordered linked list.
Function DisplayList displays the elements in the linked list and proves that an
ordered linked list has been created.

The focus of this program needs to be on function SortList. The algorithmic


logic of the SortList function can be described in the following steps:

Steps to Create an Ordered Linked List

1. Create a Front node and insert the first number in it.


2. Create a new node and place the next number in it.
3. Check if the new node belongs at the front of the list.

Chapter XXXIX Linked Lists 39.17


4. If it does, link the node directly; reassign the front pointer.
4. If it does not, traverse the list with two temporary pointers
such that the two pointers are positioned at the new
insert location. Link the new node in that position.
5. Go back to step 2 until all numbers are inserted.

// PROG3907.CPP
// This program creates an ordered linked list of integers.
// Each element of a random integer array is inserted in the
// list at the correct location. This program also shows how
// to use a user-defined pointer type.
// This program becomes an insertion sort implemented with a
// dynamic linked list data structure.

#include <iostream.h>
#include <conio.h>
#include <stdlib.h>
#include "APVECTOR.H"

struct ListNode
{
int Info;
ListNode* Next;
};

typedef ListNode* ListPtr;


typedef apvector <int> ArrayType;

void CreateList(ArrayType &A);


void SortList(const ArrayType &A, ListPtr &F);
void DisplayList(ListPtr P);

void main()
{
ArrayType List;
ListPtr Front;
CreateList(List);
SortList(List,Front);
DisplayList(Front);
}

void CreateList(ArrayType &A)


// This function creates an array A with random integers.

39.18 Exposure C++, Part IV, Abstract Data Types 12-08-99


// Each integer is displayed after it is assigned to the array
// to indicate that a random list is created.
{
int K, N;
clrscr();
cout << "Enter how many numbers ===>> ";
cin >> N;
A.resize(N);
cout << endl;
for (K = 0; K < N; K++)
{
A[K] = random(9000) + 1000;
cout << A[K] << " ";
}
cout << endl;
}

void DisplayList(ListPtr P)
// This function displays the data in the linked list created
// by the SortList function.
{
cout << endl;
while (P != NULL)
{
cout << P->Info << " ";
P = P->Next;
}
getch();
}

void SortList(const ArrayType &A, ListPtr &F)


// This function creates an ordered linked with the steps
// described immediately before this program listing.
{
int K;
int N = A.length();
ListPtr P;
ListPtr T1,T2;
// create first node and store random number in node
P = new ListNode;
F = P;
P->Info = A[0];
P->Next = NULL;
for (K = 1; K < N; K++)
{
// create new node and store random number in node
P = new ListNode;
P->Info = A[K];
if (P->Info < F->Info)
// new node is inserted in front of existing list
{
P->Next = F;
F = P;

Chapter XXXIX Linked Lists 39.19


}
else
// new node will be inserted in middle or back of the list
{
T1 = F;
while ((P->Info > T1->Info) && (T1 != NULL))
// traverse the list to find proper insert location
{
T2 = T1;
T1 = T1->Next;
}
T2->Next = P;
if (T1 == NULL)
// new node is inserted at the back of existing list
P->Next = NULL;
else
// new node is inserted in the middle of existing list
P->Next = T1;
}
}
}

PROG3907.CPP OUTPUT

Enter how many numbers ===>> 10

1095 1035 4016 1299 4201 2954 5832 2761 7302 9549

1035 1095 1299 2761 2954 4016 4201 5832 7302 9549

39.6 Deleting from an Ordered Linked List

The previous section created an ordered linked list. The primary tool used to
create the list was a set of temporary pointers, placed properly in the existing list,
to facilitate inserting each new node. In this section we will look at an existing
ordered linked list and delete specified nodes from the list.

In the next program example a simple, artificial list is created. Using a series of
ordered integers, the linked list becomes automatically ordered with less code
involved. This program needs to concentrate on deletion, not on insertion.

39.20 Exposure C++, Part IV, Abstract Data Types 12-08-99


You will find that our trusty temporary pointers can also do a good job deleting a
node. Make sure that one pointer find the node to be deleted, and a second
pointer is attached to the previous node. This scenario is shown below. Our
object is to delete the node with the K data.

[T1] [T2]

A G K M T

[T1] [T2]

A G K M T

After the links are reconnected and the unwanted node is no longer part of the
list, some process removes the node completely. The result is the next picture
with a clean list and the K node is nowhere to be seen.

A G M T

It is easy to argue that the deletion process does not require two temporary
pointers. The single pointer attached to the node, immediately before the target
node, will effectively take the target node out off the linked list. This is true, but
a pointer needs to be attached to the target node so that it can be properly deleted
and its memory space returned to the heap.

// PROG3908.CPP
// This program demonstrates how to delete an element from an
// ordered linked list. The ordered linked list is artificially
// created to simplify the program.

#include <iostream.h>
#include <conio.h>
#include <stdlib.h>

struct ListNode
{
int Info;
ListNode* Next;

Chapter XXXIX Linked Lists 39.21


};

typedef ListNode* ListPtr;

void CreateList(ListPtr &F);


void DisplayList(ListPtr F);
void DeleteNode(ListPtr &F);

void main()
{
ListPtr Front;
CreateList(Front);
DisplayList(Front);
DeleteNode(Front);
DisplayList(Front);
}

void CreateList(ListPtr &F)


{
int K;
int N;
ListPtr P,Temp;
clrscr();
cout << "Enter how many numbers ===>> ";
cin >> N;
P = new ListNode;
P->Info = 100;
P->Next = NULL;
Temp = P;
F = P;
for (K = 2; K <= N; K++)
{
P = new ListNode;
P->Info = K * 100;
P->Next = NULL;
Temp->Next = P;
Temp = P;
}
}

void DeleteNode(ListPtr &F)


{
cout << endl << endl;
cout << "Enter value of node to be deleted ===>> ";
int Value;
ListPtr Temp1 = F;

39.22 Exposure C++, Part IV, Abstract Data Types 12-08-99


ListPtr Temp2;
cin >> Value;
while (Temp1->Next->Info != Value && Temp1 != NULL)
Temp1 = Temp1->Next;
Temp2 = Temp1->Next;
Temp1->Next = Temp2->Next;
delete Temp2;
}

void DisplayList(ListPtr P)
{
cout << endl << endl;
while (P != NULL)
{
cout << P->Info << " ";
P = P->Next;
}
getch();
}

We will not be quickly satisfied with this program by executing one quick sample
to check for accuracy. With this program let us thoroughly investigate to see
what happens in a variety of different cases.

PROG3908.CPP OUTPUT #1

Enter how many numbers ===>> 10

100 200 300 400 500 600 700 800 900 1000

Enter value of node to deleted ===>> 500

100 200 300 400 600 700 800 900 1000

Output #1 deletes an existing node from the middle of the ordered list. The
program works correctly, as expected, and target node (500) is removed.

PROG3908.CPP OUTPUT #2

Enter how many numbers ===>> 10

100 200 300 400 500 600 700 800 900 1000

Enter value of node to deleted ===>> 1000

Chapter XXXIX Linked Lists 39.23


100 200 300 400 500 600 700 800 900

Output #2 deletes an existing node from the end of the ordered list. The program
works correctly, as expected, and target node (1000) is removed.

PROG3908.CPP OUTPUT #3

Enter how many numbers ===>> 10

100 200 300 400 500 600 700 800 900 1000

Enter value of node to deleted ===>> 100

100 200 300 400 500 600 700 800 900 1000

Output #3 deletes an existing node from the front of the ordered list. The
program does not work as expected. The target node (100) is not removed from
the list.

PROG3908.CPP OUTPUT #4

Enter how many numbers ===>> 0

100

Enter value of node to deleted ===>> 100

100

Output #4 is supposed to create a list with 0 nodes. The program incorrectly


displays a single node and then fails to remove this single node.

You may wonder why a program is presented that appears to have various flaws
in it. The program appears to delete target nodes ... part of the time. This is not
exactly the type of program that students should be studying as a good case study
to be followed. However, an important point is made here. Many programs are
flawed because programmers fail to consider all the possible cases involved.

39.24 Exposure C++, Part IV, Abstract Data Types 12-08-99


Furthermore, students with a good knowledge of computer science frequently do
poorly on the free response portion of the AP Examination because they do not
consider all the different possibilities.

APCS Examination Alert

Many APCS free response questions involve considering


multiple cases. Questions with linked lists always require
that different cases are considered.

The majority of AP students do not get full credit on linked


list questions because one or more cases is ignored and
the student’s solution will not work for every possible situation.

39.7 Considering all Possible Cases

This section is aimed to prevent the problems mentioned with the previous
section. Essentially, we will look once again at an ordered linked list, both from
the insertion and deletion point of view. However, we now wish to be very
thorough and consider all the possible cases. So starting with insertion, what
possible situation might arise?

A list of cases follows below. Would you have thought of all these possibilities?
Do you find that perhaps some cases have been left out? After all, who said that
the author of this stuff is without mistakes. Let’s face it, you guys are now in
chapter 39, and if you have not noticed that I make mistakes by now, you have
not been reading very carefully.

Possible Insertion Cases

Chapter XXXIX Linked Lists 39.25


 Insert into a completely empty list
 Insert in front of an existing list
 Insert at the end of an existing list
 Insert somewhere in the middle of an existing list

Check out program PROG3909.CPP and see if all the cases above are taking
into consideration. A good start is to test the program such that each case will be
considered and then check carefully if the test yields the expected results.
Students are so frequently excited with a solution, both on paper and on the
computer, that they do not stop to check the solution thoroughly.

Time and again I have seen students satisfied with the correct output of a single
testing case. Curb your enthusiasm for completion until after you have tested the
program execution very thoroughly with a wide selection of test data.

// PROG3909.CPP
// This program demonstrates inserting into an ordered
// linked list with consideration of all possible cases.

#include <iostream.h>
#include <conio.h>
#include <stdlib.h>

struct ListNode
{
int Info;
ListNode* Next;
};

typedef ListNode* ListPtr;

void CreateList(ListPtr &F);


void DisplayList(ListPtr F);
void InsertNode(ListPtr &F);

39.26 Exposure C++, Part IV, Abstract Data Types 12-08-99


void main()
{
ListPtr Front;
CreateList(Front);
DisplayList(Front);
InsertNode(Front);
DisplayList(Front);
}

void CreateList(ListPtr &F)


// This function creates some artificial ordered list to test
// the insert function.
{
int K;
int N;
ListPtr P,Temp;
clrscr();
cout << "Enter how many numbers ===>> ";
cin >> N;
if (N == 0)
F = NULL;
else
{
P = new ListNode;
P->Info = 100;
P->Next = NULL;
Temp = P;
F = P;
for (K = 2; K <= N; K++)
{
P = new ListNode;
P->Info = K * 100;
P->Next = NULL;
Temp->Next = P;
Temp = P;
}
}
}

void Insert(ListPtr &F, int Value)


// This is the function that considers all the possible cases
// and insert a new node in the correct location.
{
ListPtr Temp1 = new ListNode;
Temp1->Info = Value;
if (F == NULL || Value < F->Info)
{
Temp1->Next = F;
F = Temp1;
}
else
{
ListPtr Temp2 = F;

Chapter XXXIX Linked Lists 39.27


while (Temp2->Next != NULL && Value > Temp2->Next->Info)
Temp2 = Temp2->Next;
Temp1->Next = Temp2->Next;
Temp2->Next = Temp1;
}
}

void InsertNode(ListPtr &F)


// This function asks the user for some new node value to be
// inserted in an ordered list. Function InsertNode calls
// function Insert to actually process the insertion.
{
cout << endl << endl;
cout << "Enter value of node to be inserted ===>> ";
int Value;
cin >> Value;
Insert(F,Value);
cout << Value << " has been inserted in the list" << endl;
}

void DisplayList(ListPtr P)
// This function displays the list
{
cout << endl << endl;
while (P != NULL)
{
cout << P->Info << " ";
P = P->Next;
}
getch();
}

PROG3909.CPP OUTPUT #1

Enter how many numbers ===>> 6

100 200 300 400 500 600

Enter value of node to be inserted ===>> 350


350 has been inserted in the list

100 200 300 350 400 500 600

Output #1 inserts a new node in the middle of an existing list. The program
works as expected. The new node (350) is inserted properly.

39.28 Exposure C++, Part IV, Abstract Data Types 12-08-99


PROG3909.CPP OUTPUT #2

Enter how many numbers ===>> 6

100 200 300 400 500 600

Enter value of node to be inserted ===>> 50


50 has been inserted in the list

50 100 200 300 400 500 600

Output #2 inserts a new node in the front of an existing list. The program works
as expected. The new node (50) is inserted properly.

PROG3909.CPP OUTPUT #3

Enter how many numbers ===>> 6

100 200 300 400 500 600

Enter value of node to be inserted ===>> 700


700 has been inserted in the list

100 200 300 400 500 600 700

Output #3 inserts a new node at the end of an existing list. The program works as
expected. The new node (700) is inserted properly.

PROG3909.CPP OUTPUT #4

Enter how many numbers ===>> 0

Enter value of node to be inserted ===>> 100


100 has been inserted in the list

100

Output #4 insert a new node in an non-existing list. The program works as


expected. The new node (100) starts a new list, with one node, properly.

Chapter XXXIX Linked Lists 39.29


Switch from Insertion to Deletion

We now move on and investigate the deletion process. Are the number of
different cases the same as they were for insertion? Are there more or less? Look
at the list below and see if you agree?

Possible Deletion Cases

 Delete from a completely empty list


 Delete from the front of an existing list
 Delete from the end of an existing list
 Delete from somewhere in the middle of an existing list
 Attempt deletion when the target node is not present

You can see that the deletion cases are not exactly the same as the insertion cases.
One major difference is that it is always possible to insert a new node, assuming
that memory space is available. On the other hand, deletion is only possible if the
target node exists in a given list. Look at program PROG3909.CPP, on the next
page, and see if all the cases are covered.

// PROG3910.CPP
// This program demonstrates deleting from an ordered
// linked list with consideration of all possible cases.

#include <iostream.h>
#include <conio.h>
#include <stdlib.h>
#include "BOOL.H"

struct ListNode
{
int Info;
ListNode* Next;
};

39.30 Exposure C++, Part IV, Abstract Data Types 12-08-99


typedef ListNode* ListPtr;

void CreateList(ListPtr &F);


void DisplayList(ListPtr F);
void DeleteNode(ListPtr &F);

// The main function calls DeleteNode, which in turn will call


// function Remove to do the actual case checking and deletion
// of the target node.

void main()
{
ListPtr Front;
CreateList(Front);
DisplayList(Front);
DeleteNode(Front);
DisplayList(Front);
}

void CreateList(ListPtr &F)


// This function creates an artificial ordered list for
// deletion test purposes.
// Note that this function will not erroneously create a
// single node list when zero (0) is entered.
{
int K;
int N;
ListPtr P,Temp;
clrscr();
cout << "Enter how many numbers ===>> ";
cin >> N;
if (N == 0)
F = NULL;
else

{
P = new ListNode;
P->Info = 100;
P->Next = NULL;
Temp = P;
F = P;
for (K = 2; K <= N; K++)
{
P = new ListNode;
P->Info = K * 100;
P->Next = NULL;
Temp->Next = P;

Chapter XXXIX Linked Lists 39.31


Temp = P;
}
}
}

void Remove(ListPtr &F, int Value, bool &Exists)


// Function Remove checks all the possible cases and actually
// removes the target node.
{
if (F == NULL)
Exists = false;
else
{
ListPtr Temp1 = F;
if (F->Info == Value)
{
F = F->Next;
delete Temp1;
}
else
{
ListPtr Temp2;
while (Temp1->Next->Info != Value && Temp1->Next != NULL)
Temp1 = Temp1->Next;
if (Temp1->Next == NULL)
Exists = false;
else
{
Temp2 = Temp1->Next;
Temp1->Next = Temp2->Next;
delete Temp2;
Exists = true;
}
}
}
}

void DeleteNode(ListPtr &F)


// Function DeleteNode asks the user for a target node to be
// deleted and calls function Remove to handle the process.
{
cout << endl << endl;
int Value;
cout << "Enter value of node to be deleted ===>> ";
cin >> Value;
bool Exists;
Remove(F,Value,Exists);
cout << endl;
if (Exists)
cout << Value << " has been deleted from the list." << endl;
else
cout << Value << " was not found in the list." << endl;
}

39.32 Exposure C++, Part IV, Abstract Data Types 12-08-99


void DisplayList(ListPtr P)
// Function DisplayList traverses and displays the values of the
// ordered linked list.
{
cout << endl << endl;
while (P != NULL)
{
cout << P->Info << " ";
P = P->Next;
}
getch();
}

PROG3910.CPP OUTPUT #1

Enter how many numbers ===>> 6

100 200 300 400 500 600

Enter value of node to be deleted ===>> 350


350 was not found in the list

100 200 300 400 500 600

Output #1 tries to delete a target node from an existing list. The program works
as expected. The target node (350) does not exist in the list and a message
indicates that the node was not found.

PROG3910.CPP OUTPUT #2

Enter how many numbers ===>> 6

100 200 300 400 500 600

Enter value of node to be deleted ===>> 300


300 has been deleted from the list

100 200 400 500 600

Output #2 deletes a node from the middle of an existing list. The program works
as expected. The target node (300) is deleted properly.

Chapter XXXIX Linked Lists 39.33


PROG3910.CPP OUTPUT #3

Enter how many numbers ===>> 6

100 200 300 400 500 600

Enter value of node to be deleted ===>> 100


100 has been deleted from the list

200 300 400 500 600

Output #3 deletes a node from the front of an existing list. The program works as
expected. The target node (100) is deleted properly.

PROG3910.CPP OUTPUT #4

Enter how many numbers ===>> 6

100 200 300 400 500 600

Enter value of node to be deleted ===>> 600


600 has been deleted from the list

100 200 300 400 500

Output #4 deletes a node from the end of an existing list. The program works as
expected. The target node (600) is deleted properly.

PROG3910.CPP OUTPUT #5

Enter how many numbers ===>> 0

Enter value of node to be deleted ===>> 100


100 was not found in the list

Output #5 tries to delete a target node from a non-existing list. The program
works as expected. The target node (100) does not exist in the list and a message
indicates that the node was not found.

39.34 Exposure C++, Part IV, Abstract Data Types 12-08-99


39.8 Linked Lists and Memory Locations

Consider the linked list diagram below. It is a lovely list with five nodes. Each
node has one field for character data and a second field to store the pointer to the
next node in the list. F point to the first node in the linked list, which is ordered
alphabetically.

[F] A G K M T

Now all this linked list stuff and diagrams with nodes and pointers is terrific, but
hopefully you do not expect to look inside the computer and find a bunch of
pointers that link different memory locations together. At least you should not
expect any type of arrow-shaped pointers. You have worked with pointers
before. A pointer stores a memory address. So let’s get a little more technical
and represent the linked list in a manner that resembles reality more closely.

The diagram, shown later, represents memory cells. Each cell is identified by a
base-16 memory address like @7b00. The @ indicates address in this
illustration. Each memory cell is four bytes. Two bytes are for the integer data
field and another two bytes are for the pointer data field. Keep in mind that not
every compiler allocates memory in the exact same manner. The importance here
is to visualize a memory grid of addresses drawn such that every cell can hold the
information of one node in the linked list. Now also keep in mind that there is
one pointers, F the Front pointer, which needs to be stored somewhere.

A pointer may store a memory address, but this memory address in turn needs to
be stored somewhere. The space requirement for the front pointer is technically
only two bytes. The illustration, on the next page, may give the impression that
four bytes are needed which is not true.

The diagram represents a top view of a segment of the computer’s memory. In


particular note that some memory locations contain addresses of other memory
locations. This is precisely what a pointer is. It represents the Next pointer of the
linked list.

The linked list diagram, with its arrow-style pointers, is drawn again above the
memory segment diagram. This allows a clear comparison between the two types
of linked list representations.

Chapter XXXIX Linked Lists 39.35


[F] A G K M T

@7b00 @7b04 @7b08 @7b0c @7b10 @7b14 @7b18 @7b1c

@7b44 M
@7b94
@7b30 @7b34 @7b38 @7b3c @7b40 @7b44 @7b48 @7b4c

G A
@7b68 @7b30
@7b60 @7b64 @7b68 @7b6c @7b70 @7b74 @7b78 @7b7c

K
@7b1c

@7b90 @7b94 @7b98 @7b9c @7ba0 @7ba4 @7ba8 @7bac

T
@0000

Let us step through this diagram and see if you can visualize the linked list that is
represented here. It is possible that many of you have little trouble with the
visualization because you look at the diagram at the top of the page.

Step-1 The Front pointer occupies @7b08


The pointer store the address of the first node, @7b44.

Step-2 The memory cell at @7b44 stores character A.


It also stores the address of the next node, @7b30.

Step-3 The memory cell at @7b30 stores character G.


It also stores the address of the next node, @7b68.

Step-4 The memory cell at @7b68 stores character K.


It also stores the address of the next node, @7b1c.

Step-5 The memory cell at @7b1c stores character M.


It also stores the address of the next node, @7b94.

Step-6 The memory cell at @7b94 stores character T.


It also stores the address of the next node, @0000.
This is NULL address and indicates the end of the linked list.

39.36 Exposure C++, Part IV, Abstract Data Types 12-08-99


39.9 Practice Exercises

The exercises that follow will look quite different than any previous multiple
choice questions. For each question you will be provided with a diagram that
illustrates a linked list at the start of the question. A number of program
statements follow that alters the storage in the linked list. Your job is then to
determine which one of the diagrams that follow represents the new linked list.
This style of question was developed to encourage students to visualize the linked
lists that they use. You will also find a number of questions on this style on the
APCS Examination.

The answers of these exercises will not be explained. However, at the end of the
section the answers are provided so you can check your logic. Draw pictures of
the different stages of the linked list. Be especially careful not to be off by one
node. There is quite a difference between the following two statements:

while(P != NULL)
while(P->Next != NULL)

Please be aware that various exercises are designed to test your ability to interpret
the syntax and logic of linked lists implementations. Some examples may use
statements that should not be used in real programs.

Exercises 1-10 refer to the following declarations:

struct ListNode
{
char Data;
ListNode * Next;
};
ListNode *P1, *P2, *P3;

In the exercises that follow you will be shown some initial list configuration. Do
not be concerned how this list was developed. Look at the list and then consider
the program statements that follow. At the conclusion of executing the provided
program statements you need to select the diagram that represents the new
configuration of the linked list. Note that only the list configuration with linking
pointers is shown after the program segment has finished execution. Any of the P
pointers are intentionally not illustrated to make the diagrams less cluttered.

Chapter XXXIX Linked Lists 39.37


01. Suppose that P1 represents the following list.

[P1]

A B C D

How is the linked list represented after the program segment below executes?

P2 = new ListNode;
P2->Data = 'E';
P1-Data = P2->Data;

(A) A B C D

(B) A B C E

(C) E B C D

(D) E E E E

02. Suppose that P1 represents the following list.

[P1]

A B C D

How is the linked list represented after the program segment below executes?

P2 = new ListNode;
P2->Data = 'E';
while (P1->Next != NULL)
P1 = P1->Next;
P1->Data = P2->Data;

(A) A B C D

(B) A E C D

(C) A B C E

(D) A B E D

39.38 Exposure C++, Part IV, Abstract Data Types 12-08-99


03. Suppose that P1 represents the following list.

[P1]

A B C D

How is the linked list represented after the program segment below executes?

P2 = new ListNode;
P2->Data = 'E';
while (P1->Next->Next != NULL)
P1 = P1->Next;
P1->Data = P2->Data;

(A) A B C D

(B) A E C D

(C) A B C E

(D) A B E D

04. Suppose that P1 represents the following list.

[P1]

A B C D

How is the linked list represented after the program segment below executes?

P2 = new ListNode;
P2->Data = 'E';
while (P1->Next->Next->Next != NULL)
P1 = P1->Next;
P2->Data = P1->Data;

(A) A B C D

(B) A E C D

(C) A B C E

(D) A B E D

Chapter XXXIX Linked Lists 39.39


05. Suppose that P1 represents the following list.

[P1]

A B C D

How is the linked list represented after the program segment below executes?

while (P1->Next != NULL)


{
P2 = P1;
P1 = P1->Next;
P1->Data = P2->Data;
}

(A) A B C D

(B) D C B A

(C) D D D D

(D) A A A A

06. Suppose that P1 represents the following list.

[P1]

A B C D

How is the linked list represented after the program segment below executes?

P2 = P1->Next->Next->Data;
while (P1->Next != NULL)
{
P1 = P1->Next;
P1->Data = P2->Data;
}

(A) A B C D

(B) C C C C

(C) A B C C

(D) C C C D

39.40 Exposure C++, Part IV, Abstract Data Types 12-08-99


07. Suppose that P1 represents the following list.

[P1]

A B C D

How is the linked list represented after the program segment below executes?

P2 = new ListNode;
P2->Data = 'E';
P2->Next = NULL;
while (P1->Next != NULL)
P1 = P1->Next;
P1->Next = P2;

(A) A B C D E

(B) A B C E D

(C) A B C E

(D) A B D C

08. Suppose that P1 represents the following list.

[P1]

A B C D

How is the linked list represented after the program segment below executes?

P2 = new ListNode;
P2->Data = 'E';
while (P1->Next->Next != NULL)
{
P2 = P1;
P1 = P1->Next;
P2->Data = P1->Data;
}

(A) A B C D E

(B) B C D E A

(C) B C D D

(D) B C D E

Chapter XXXIX Linked Lists 39.41


09. Suppose that P1 represents the following list.

[P1]

A B C D

How is the linked list represented after the program segment below executes?

P2 = new ListNode;
P2->Data = 'E';
P2->Next = NULL;
while (P1->Data != 'C')
{
P3 = P1;
P1 = P1->Next;
}
P3->Next = P2;
P2->Next = P1;

(A) A B C E D

(B) A B E C D

(C) A E B C D

(D) A B C D E

10. Suppose that P1 represents the following list.

[P1]

A B C D

How is the linked list represented after the program segment below executes?

P3 = new ListNode;
while (P1->Next != NULL)
{
P2 = P1;
P1 = P1->Next;
P3->Data = P1->Data;
P1->Data = P2->Data;
P2->Data = P3->Data;
}

(A) A B C D

(B) A B C E

(C) B C D A

39.42 Exposure C++, Part IV, Abstract Data Types 12-08-99


(D) D C B
A
Exercise Answers
1–C 6–B
2–C 7–A
3–D 8–C
4–B 9–B
5–D 10 – C

Chapter XXXIX Linked Lists 39.43

You might also like