1 / 33

Linked List (II)

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

leoma
Télécharger la présentation

Linked List (II)

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. ECE230 Lectures Series Linked List (II) Ying Wu Electrical & Computer Engineering Northwestern University yingwu@ece.northwestern.edu

  2. 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

  3. 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; }

  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. firstPtr lasttPtr H E L L O List

  6. 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 };

  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. firstPtr 5 7 9 newPtr insertAtFront if ( isEmpty() ) // List is empty firstPtr = lastPtr = newPtr; else { // List is not empty newPtr->nextPtr = firstPtr; firstPtr = newPtr; }

  11. 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; }

  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 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 }

  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. 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 }

  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 tempPtr Destruction if ( !isEmpty() ) { // List is not empty Node *curPtr = firstPtr, *tempPtr; while ( curPtr != 0 ) { tempPtr = curPtr; curPtr = curPtr->nextPtr; delete tempPtr; } }

  19. ~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"; }

  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 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

  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 • Why don’t I overload an operator? Node& List::operator[](const int & index) { return Index(index); }

  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 0 Node *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. 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!

  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?

More Related