Date post: | 18-Dec-2015 |
Category: |
Documents |
Upload: | molly-parks |
View: | 218 times |
Download: | 0 times |
1
Linked List (II)
Ying Wu Electrical Engineering & Computer
ScienceNorthwestern [email protected]
EECS 230 Lectures Series
2
Self-Referential Classes
self-referential class– class that contains a pointer to a class object of the
same type– can be linked together to form useful data
structures such as lists, queues, stacks and trees– terminated with a NULL pointer (0)
Two self-referential class objects linked together 1015
NULL pointer (points to nothing)Data member and pointer
3
Node Classclass Node {
public:
Node( const int & ); // constructor
int getData() const; // return data in the node
int data; // data. Actually, it can be other types or classes
Node *nextPtr; // next node in the list
};
// Constructor
Node::Node( const int &info )
: data( info ), nextPtr( 0 ) { }
// Return a copy of the data in the node
Node::getData() const { return data; }
4
Linked Lists
linked list – linear collection of self-referential class objects,
called nodes, connected by pointer links– accessed via a pointer to the first node of the list– subsequent nodes are accessed via the link-
pointer member– the link pointer in the last node is set to null to
mark the list’s end
Use a linked list instead of an array when– the number of data elements is unpredictable – the list needs to be sorted
6
class List {
public:
List(); // constructor
~List(); // destructor
void insertAtFront( const int & );
void insertAtBack( const int & );
bool removeFromFront( int & );
bool removeFromBack( int & );
bool isEmpty() const;
void print() const;
int Length() const;
Node& Search( const int& data) const;
Node& Index(const int& index);
Node& operator[](const int& index);
bool insertAfter( const int& data, const int& pos);
private:
Node *firstPtr; // pointer to first node
Node *lastPtr; // pointer to last node
Node *getNewNode( const int & ); // Utility to allocate a new node
};
7
// constructor
List::List() :
firstPtr( 0 ),
lastPtr( 0 )
{
// empty
}
// Is the List empty?
bool
List::isEmpty() const
{
return firstPtr == 0;
}
8
// Return a pointer to a newly allocated node
Node *List::getNewNode( const int &value )
{
Node *ptr = new Node( value ); // look at this!
assert( ptr != 0 );
return ptr;
}
// Display the contents of the List
void List::print() const
{
if ( isEmpty() ) {
cout << "The list is empty\n\n";
return;
}
Node *currentPtr = firstPtr;
cout << "The list is: ";
while ( currentPtr != 0 ) {
cout << currentPtr->data << ' ';
currentPtr = currentPtr->nextPtr; // like the increment operation
}
cout << "\n\n";
}
9
void List::insertAtFront( const int & value){ Node *newPtr = getNewNode(value);
if ( isEmpty() ) // List is empty: trivial case
firstPtr = lastPtr = newPtr;
else { // List is not empty: non-trivial case
newPtr->nextPtr = firstPtr; // step 1
firstPtr = newPtr; // step 2
}
}
void List::insertAtBack( const int& value)
{
Node *newPtr = getNewNode(value);
if ( isEmpty() ) // List is empty: trivial case
firstPtr = lastPtr = newPtr;
else { // List is not empty: non-trivial case
lastPtr->nextPtr = newPtr; // step 1
lastPtr = newPtr; // step 2
}
}
10
insertAtFront
5
newPtr
7 9
firstPtr
if ( isEmpty() ) // List is empty firstPtr = lastPtr = newPtr;
else { // List is not empty
newPtr->nextPtr = firstPtr;
firstPtr = newPtr;
}
11
insertAtBack
5
newPtr
7 9
firstPtr
lastPtr
if ( isEmpty() ) // List is empty firstPtr = lastPtr = newPtr;
else { // List is not empty
lastPtr->nextPtr = newPtr;
lastPtr = newPtr;
}
12
bool List::removeFromFront( int & value){ if ( isEmpty() ) // List is empty
return false; // delete unsuccessful
else {
Node *tempPtr = firstPtr; // step I: remember what to delete
if ( firstPtr == lastPtr ) // trivial case
firstPtr = lastPtr = 0;
else // non-trivial case
firstPtr = firstPtr->nextPtr; // step II
value = tempPtr->data; // step III: retrieve data (option)
delete tempPtr; // step IV: recycle
return true; // delete successful
}
}
Question: what if I don’t do step I?
13
firstPtr lastPtr
7 9 5 3
removeFromFront
tempPtr
if ( isEmpty() ) // List is empty
return false; // delete unsuccessful
else {
Node *tempPtr = firstPtr; // step I
if ( firstPtr == lastPtr )
firstPtr = lastPtr = 0;
else
firstPtr = firstPtr->nextPtr; // step II
value = tempPtr->data; // step III: data being removed
delete tempPtr; // step IV
return true; // delete successful
}
14
bool List::removeFromBack( int & value){ if ( isEmpty() )
return false; // delete unsuccessful
else {
Node *tempPtr = lastPtr; // step I: remember what to delete
if ( firstPtr == lastPtr ) // trivial case
firstPtr = lastPtr = 0;
else { // non-trivial case
Node *currentPtr = firstPtr; // step II: find “next to last”
while ( currentPtr->nextPtr != lastPtr )
currentPtr = currentPtr->nextPtr;
lastPtr = currentPtr; // step III:
currentPtr->nextPtr = 0; // step IV: “housekeeping”
}
value = tempPtr->data; // step V: retrieve data deleted
delete tempPtr; // step VI: recycle
return true; // delete successful
}
}
Note: The most important part is step II.
15
removeFromBackfirstPtr lastPtr
7 9 5 3
tempPtrcurPtr
if ( isEmpty() )
return false; // delete unsuccessful
else {
Node *tempPtr = lastPtr;
if ( firstPtr == lastPtr )
firstPtr = lastPtr = 0;
else {
Node *currentPtr = firstPtr;
while ( currentPtr->nextPtr != lastPtr )
currentPtr = currentPtr->nextPtr;
lastPtr = currentPtr;
currentPtr->nextPtr = 0;
}
value = tempPtr->data;
delete tempPtr;
return true; // delete successful
}
16
Questions
How to delete the list? How do I know the length of the
list? How to index? How can we search a node? How to insert a node in between?
18
curPtr
7 9 5 3
Destruction
tempPtr if ( !isEmpty() ) { // List is not empty
Node *curPtr = firstPtr, *tempPtr;
while ( curPtr != 0 ) {
tempPtr = curPtr;
curPtr = curPtr->nextPtr;
delete tempPtr;
}
}
19
List::~List()
{
if ( !isEmpty() ) { // List is not empty
cout << "Destroying nodes ...\n";
Node *currentPtr = firstPtr, *tempPtr;
while ( currentPtr != 0 ) { // delete remaining nodes
tempPtr = currentPtr;
cout << tempPtr->data << '\n';
currentPtr = currentPtr->nextPtr;
delete tempPtr;
}
}
cout << "All nodes destroyed\n\n";
}
~List()
20
void main()
{
List mylist;
instructions();
int choice, value;
do {
cout << "? "; cin >> choice;
switch ( choice ) {
case 1: cin >> value;
mylist.insertAtFront( value ); mylist.print();
break;
case 2: cin >> value;
mylist.insertAtBack( value ); mylist.print();
break;
case 3: if ( mylist.removeFromFront( value ) )
cout << value << " removed from list\n";
mylist.print();
break;
case 4: if ( mylist.removeFromBack( value ) )
cout << value << " removed from list\n";
mylist.print();
break;
}
} while ( choice != 5 );
}
void instructions()
{
cout << "Enter one of the following:\n"
<< " 1 to insert at beginning of list\n"
<< " 2 to insert at end of list\n"
<< " 3 to delete from beginning of list\n"
<< " 4 to delete from end of list\n"
<< " 5 to end list processing\n";
}
21
Testing a List of integer valuesEnter one of the following: 1 to insert at beginning of list 2 to insert at end of list 3 to delete from beginning of list 4 to delete from end of list 5 to end list processing? 11The list is: 1 ? 12The list is: 2 1 ? 23The list is: 2 1 3 ? 24The list is: 2 1 3 4 ? 32 removed from listThe list is: 1 3 4 ? 31 removed from listThe list is: 3 4
? 44 removed from listThe list is: 3 ? 43 removed from listThe list is empty ? 5End list test
22
The Length?
int List::Length( ){
int length = 0;Node *curPtr = firstPtr;while(curPtr != NULL){
length ++;curPtr = curPtr->nextPtr;
}return length;
}
23
Index the list?
Node& List::Index(const int& index){
int count = index;Node *curPtr = firstPtr;Node *dPtr = NULL; // WHY?while(curPtr != NULL){
if (count == 0){dPtr = curPtr;break;
}count --;curPtr = curPtr->nextPtr;
}if (dPtr == NULL) cout << “out of range!\n” ;return (*dPtr); // WHY?
}
24
A more intuitive way
Node& List::operator[](const int & index)
{
return Index(index);
}
Why don’t I overload an operator?
25
Search for a node?
Give a specific data Want to check if the data is inside
the list Return the address of the node if
inside Return NULL otherwise
26
Search?Node& List::Search( const int& data){
Node *dPtr = 0; // NULL is 0Node *curPtr = firstPtr;while(curPtr != NULL){
if ( curPtr->data == data){cout << “found!” << endl;dPtr = curPtr;break;
}curPtr = curPtr->nextPtr;
}return (*dPtr);
}
27
Insert in between?
Given:– A piece of data– A position of the list
Insert the data after the position of the list
28
bool List::insertAfter(const int& data, const int& pos){
Node* curPtr = & (Index(pos));if (!curPtr){
cout << “Error: insertAfter\n”;return false;
}else{
Node* newPtr = getNewNode(data);Node* nPtr = curPtr->nextPtr;
curPtr->nextPtr = newPtr;newPtr->nextPtr = nPtr;
if ( nPtr == NULL) // i.e., curPtr is the last onelastPtr = newPtr;
return true;}
}
Insert?
Note: this one has several very good ideas, please study hard on this function!
29
void main()
{
List mylist;
instructions();
int choice, value, pos;
Node *dPtr;
do {
cout << "? ";
cin >> choice;
switch ( choice ) {
case 1:
cin >> value;
mylist.insertAtFront( value );
mylist.print();
break;
case 2:
cin >> value;
mylist.insertAtBack( value );
mylist.print();
break;
case 3:
if ( mylist.removeFromFront( value ) )
cout << value << " removed from list\n";
mylist.print();
break;
30
case 4:
if ( mylist.removeFromBack( value ) )
cout << value << " removed from list\n";
mylist.print();
break;
case 5:
cin >> value;
dPtr = &mylist.Search( value);
if (dPtr)
cout << dPtr->getData() << " found in the list\n";
else
cout << value << " is not inside the list\n";
break;
case 6:
cin >> pos; // for indexing
dPtr = &mylist[pos];
if(dPtr)
cout << "List["<<pos<<"]="<< mylist[pos].getData() << endl;
else
out << "wrong!" << endl;
break;
31
case 7:
cin >> value >> pos;
if (mylist.insertAfter(value, pos)){
cout << "insert " << value << " after " << pos << " done\n";
mylist.print();
}
else
cout << "can not be insert!\n";
break;
default:
break;
}
} while ( choice != 8 );
}
32
Summary
What motivates the use of linked list?
What defines a Node? What is a List? How to destruct a list? How to search a list? How to insert data into a list?