33
1 Linked List (II) Ying Wu Electrical Engineering & Computer Science Northwestern University [email protected] EECS 230 Lectures Series

1 Linked List (II) Ying Wu Electrical Engineering & Computer Science Northwestern University [email protected] EECS 230 Lectures Series

Embed Size (px)

Citation preview

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

5

Linked List

H

E

L

L

firstPtr lasttPtr

O

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?

17

Destructor

Can we just ?List::~List()

{

delete firstPtr;

}

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?

33

Question to think about

What if I want a list for other data types?