330 likes | 459 Views
ECE230 Lectures Series. Linked List (II). Ying Wu Electrical & Computer Engineering Northwestern University yingwu@ece.northwestern.edu. 15. 10. Data member and pointer. NULL pointer (points to nothing). Self-Referential Classes. self-referential class
E N D
ECE230 Lectures Series Linked List (II) Ying Wu Electrical & Computer Engineering Northwestern University yingwu@ece.northwestern.edu
15 10 Data member and pointer NULL pointer (points to nothing) 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
Node Class class 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; }
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
firstPtr lasttPtr H E L L O List
List Class 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 };
// constructor List::List() : firstPtr( 0 ), lastPtr( 0 ) { // empty } // Is the List empty? bool List::isEmpty() const { return firstPtr == 0; }
// 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"; }
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 } }
firstPtr 5 7 9 newPtr insertAtFront if ( isEmpty() ) // List is empty firstPtr = lastPtr = newPtr; else { // List is not empty newPtr->nextPtr = firstPtr; firstPtr = newPtr; }
lastPtr firstPtr 5 7 9 newPtr insertAtBack if ( isEmpty() ) // List is empty firstPtr = lastPtr = newPtr; else { // List is not empty lastPtr->nextPtr = newPtr; lastPtr = newPtr; }
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?
firstPtr lastPtr 7 9 5 3 tempPtr removeFromFront 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 }
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.
firstPtr lastPtr 7 9 5 3 tempPtr curPtr removeFromBack 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 }
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?
Destructor • Can we just ? List::~List() { delete firstPtr; }
curPtr 7 9 5 3 tempPtr Destruction if ( !isEmpty() ) { // List is not empty Node *curPtr = firstPtr, *tempPtr; while ( curPtr != 0 ) { tempPtr = curPtr; curPtr = curPtr->nextPtr; delete tempPtr; } }
~List() 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"; }
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"; }
Testing a List of integer values Enter 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 ? 1 1 The list is: 1 ? 1 2 The list is: 2 1 ? 2 3 The list is: 2 1 3 ? 2 4 The list is: 2 1 3 4 ? 3 2 removed from list The list is: 1 3 4 ? 3 1 removed from list The list is: 3 4 ? 4 4 removed from list The list is: 3 ? 4 3 removed from list The list is empty ? 5 End list test
The Length? int List::Length( ) { int length = 0; Node *curPtr = firstPtr; while(curPtr != NULL){ length ++; curPtr = curPtr->nextPtr; } return length; }
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? }
A more intuitive way • Why don’t I overload an operator? Node& List::operator[](const int & index) { return Index(index); }
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
Search? Node& List::Search( const int& data) { Node *dPtr = 0; // NULL is 0 Node *curPtr = firstPtr; while(curPtr != NULL){ if ( curPtr->data == data){ cout << “found!” << endl; dPtr = curPtr; break; } curPtr = curPtr->nextPtr; } return (*dPtr); }
Insert in between? • Given: • A piece of data • A position of the list • Insert the data after the position of the list
Insert? 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 one lastPtr = newPtr; return true; } } Note: this one has several very good ideas, please study hard on this function!
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;
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;
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 ); }
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?
Question to think about • What if I want a list for other data types?