Arrays Advantages and Disadvantages Advantages Random access of

  • Slides: 21
Download presentation
Arrays: Advantages and Disadvantages Advantages: Random access of elements is facilitated via indices. ·To

Arrays: Advantages and Disadvantages Advantages: Random access of elements is facilitated via indices. ·To find a[i], merely add i*(size of single element) to address of a[0]. ·This also facilitates sorting and searching. Enumerated list idea is easy to conceptualize. Disadvantages: A specific amount of space must be allocated. ·What if the program actually requires less space? ·What if the program actually requires more space? Altering the array’s contents can be time-consuming. ·Inserting an element inside the array requires shifting all later array elements down to make room for it. ·Removing an internal array element requires shifting all later array elements up to fill the resulting gap. Carrano - Chapter 4 CS 150 193

Linked Lists Location of first list item Data element Location of next item Data

Linked Lists Location of first list item Data element Location of next item Data element NULL indicator of last element Location of next item Data element Carrano - Chapter 4 Location of next item CS 150 Location of next item 194

Linked List Advantages A variable amount of space is allocated. ·No particular space requirements

Linked List Advantages A variable amount of space is allocated. ·No particular space requirements must be specified. ·Adequate memory is provided dynamically. ·Extra memory is not wasted. Altering the linked list’s contents is efficient. ·Inserting an element into the linked list merely requires linking the new node to its successor and linking its predecessor to the new node. Before: After: Carrano - Chapter 4 CS 150 195

Linked List Advantages (Continued) ·Removing an element from the linked list merely requires linking

Linked List Advantages (Continued) ·Removing an element from the linked list merely requires linking the node’s predecessor to its successor. Before: After: Linked List Disadvantages Random access of elements is no longer possible. ·Due to the lack of indices, the entire list must be traversed when a particular element is sought. Unenumerated list idea can be difficult to conceptualize. Carrano - Chapter 4 CS 150 196

A Linked List Class Definition in C++ // Class definition file: linked. List. h

A Linked List Class Definition in C++ // Class definition file: linked. List. h // #ifndef LINKED_LIST_H class Linked. List #include <string> { public: using namespace std; // Constructors and destructor typedef string element. Type; Linked. List(); Linked. List(const Linked. List &list); struct node; ~Linked. List(); typedef node* node. Ptr; struct node // Member functions { int size(); element. Type item; bool insert(element. Type elt); node. Ptr next; bool remove(element. Type elt); }; bool retrieve(element. Type elt, int &position); element. Type& operator [ ] (int position); Linked. List& operator = (const Linked. List &list); Note that the mutual friend istream& operator >> (istream &source. File, Linked. List &list); dependence between the friend ostream& operator << definitions of the node struct (ostream &dest. File, const Linked. List &list); and the node. Ptr type requires private: that their definitions be // Data member handled “creatively”. node. Ptr head; // Member function node. Ptr get. Node(element. Type elt); }; #define LINKED_LIST_H #endif Carrano - Chapter 4 CS 150 197

The Linked List Class Implementation // Class implementation file: linked. List. cpp // #include

The Linked List Class Implementation // Class implementation file: linked. List. cpp // #include "linked. List. h" #include <cassert> using namespace std; // The default constructor merely sets up an empty Linked. List. // Linked. List: : Linked. List() { head = NULL; } // The copy constructor makes a deep copy of the parameterized Linked. List. // Linked. List: : Linked. List(const Linked. List &list) { If list’s head is NULL, then node. Ptr curr. Ptr, this. Curr. Ptr, this. Prev. Ptr; it’s empty, so *this will also be if (list. head == NULL) head = NULL; set up that way. else { If list isn’t empty, repeatedly create head = get. Node(list. head->item); duplicate nodes and link them into *this. Prev. Ptr = head; curr. Ptr = list. head->next; in the proper order. while (curr. Ptr != NULL) { this. Curr. Ptr = get. Node(curr. Ptr->item); Notice the “arrow” notation; it’s this. Prev. Ptr->next = this. Curr. Ptr; this. Prev. Ptr = this. Curr. Ptr; equivalent to (but easier to curr. Ptr = curr. Ptr->next; understand than): } curr. Ptr = (*curr. Ptr). next; } } Carrano - Chapter 4 CS 150 198

The Linked List Class Implementation (Continued) // The assignment operator makes the current //

The Linked List Class Implementation (Continued) // The assignment operator makes the current // object a copy of the parameterized object Linked. List& Linked. List: : operator = (const Linked. List &list) { node. Ptr curr. Ptr, this. Curr. Ptr, this. Prev. Ptr; Make sure that the user if(head == list. head) is not assigning the list return *this; (*this). ~Linked. List(); to itself. if (list. head == NULL) head = NULL; else { head = get. Node(list. head->item); this. Prev. Ptr = head; The destructor must delete curr. Ptr = list. head->next; every node in the old list, while (curr. Ptr != NULL) ensuring that no unwanted { nodes remain in memory. this. Curr. Ptr = get. Node(curr. Ptr->item); this. Prev. Ptr->next = this. Curr. Ptr; this. Prev. Ptr = this. Curr. Ptr; curr. Ptr = curr. Ptr->next; } } return *this; } Carrano - Chapter 4 CS 150 199

The Linked List Class Implementation (Continued) // The destructor systematically deletes // // every

The Linked List Class Implementation (Continued) // The destructor systematically deletes // // every node in the Linked. List. // Linked. List: : ~Linked. List() { The destructor must delete node. Ptr curr. Ptr; while (head != NULL) every node in the list, { ensuring that no dangling curr. Ptr = head; pointers remain. head = head->next; curr. Ptr->next = NULL; delete curr. Ptr; } } // The size member function returns the // // number of nodes in the Linked. List. // int Linked. List: : size() { int count = 0; node. Ptr curr. Ptr = head; while (curr. Ptr != NULL) { curr. Ptr = curr. Ptr->next; count++; } return count; } Carrano - Chapter 4 CS 150 There is no data member for the size, so the nodes must be counted from scratch. 200

The Linked List Class Implementation (Continued) // The insert member function creates a new

The Linked List Class Implementation (Continued) // The insert member function creates a new // node containing the parameterized value, // inserting it at the head of the Linked. List. // A boolean value indicating whether the // insertion worked is returned. bool Linked. List: : insert(element. Type elt) { node. Ptr insert. Ptr = get. Node(elt); if (insert. Ptr == NULL) return false; if (head == NULL) head = insert. Ptr; else { insert. Ptr->next = head; head = insert. Ptr; } return true; } // // // If the get. Node function returns a NULL pointer, then it was unable to allocate adequate memory for the new node being inserted. If the list was empty, then the new node becomes the entire list. If the list wasn’t empty, then the new node is linked in to become the new head of the list. Carrano - Chapter 4 CS 150 201

The Linked List Class Implementation (Continued) // The remove member function locates the first

The Linked List Class Implementation (Continued) // The remove member function locates the first occurrence of the parameterized // // value in the Linked. List and detaches it from the Linked. List. A boolean // // value indicating whether the removal worked is returned. // bool Linked. List: : remove(element. Type elt) { node. Ptr curr. Ptr = head; node. Ptr prev. Ptr = NULL; bool found. It = false; Loop through the list, while ((!found. It) && (curr. Ptr != NULL)) keeping track of the node { being tested (to see if its if (curr. Ptr->item == elt) found. It = true; value is elt) and its else predecessor in the list. { prev. Ptr = curr. Ptr; If the sought value is curr. Ptr = curr. Ptr->next; If the sought } in the head node, then } if (found. It) { if (prev. Ptr == NULL) head = curr. Ptr->next; else prev. Ptr->next = curr. Ptr->next; delete curr. Ptr; } return found. It; } Carrano - Chapter 4 the list needs a new head. value is in a nonhead node, then its predecessor must be relinked to its successor. In either case, the first node containing the sought value must be released back into the available memory heap. CS 150 202

The Linked List Class Implementation (Continued) // The retrieve member function locates the first

The Linked List Class Implementation (Continued) // The retrieve member function locates the first occurrence of the parameterized // // value in the Linked. List and sets the parameterized node. Ptr to its memory // // location. A boolean value indicating whether the retrieval worked is returned. // bool Linked. List: : retrieve(element. Type elt, int &position) { This retrieve function must traverse bool found. It = false; node. Ptr curr. Ptr = head; the entire list until it finds the first position = 0; occurrence of the elt value. while ((!found. It) && (curr. Ptr != NULL)) It wouldn’t be made any easier in an { position++; array implementation of the list. if (curr. Ptr->item == elt) found. It = true; else curr. Ptr = curr. Ptr->next; This retrieve function traverses the } entire list until it counts off the return found. It; designated number of list nodes. } // The subscript operator retrieves the element in the parameterized position // // of the Linked. List. Note that the starting index for this operator is one. // element. Type& Linked. List: : operator [ ] (int position) { node. Ptr curr. Ptr = head; Because of an array’s use of assert((position > 0) && (position <= size())); consecutive memory addresses, it for (int i = 1; i < position; i++) would be made much easier in an curr. Ptr = curr. Ptr->next; array implementation of the list. return curr. Ptr->item; } Carrano - Chapter 4 CS 150 203

The Linked List Class Implementation (Continued) // The input operator reads all values of

The Linked List Class Implementation (Continued) // The input operator reads all values of type // // element. Type from the parameterized input stream, // // inserting them into the parameterized Linked. List, // // until the input stream has been completely depleted. // istream& operator >> (istream &source. File, Linked. List &list) { element. Type next. Elt; source. File >> next. Elt; while (!source. File. eof()) { list. insert(next. Elt); source. File >> next. Elt; } return source. File; Because the insert member function always inserts at the head of the list, the linked list will actually end up being in reverse order! } // The output operator outputs the values in the Linked. List, // // each on a separate output line in the parameterized // // output stream, starting with the head element. // ostream& operator << (ostream &dest. File, const Linked. List &list) { node. Ptr ptr; Notice the use of the for (ptr = list. head; ptr != NULL; ptr = ptr->next) for loop with a pointer dest. File << ptr->item << endl; as our iterative variable! return dest. File; } Carrano - Chapter 4 CS 150 204

The Linked List Class Implementation (Continued) // The get. Node member function creates and

The Linked List Class Implementation (Continued) // The get. Node member function creates and returns // // a new node. Ptr, pointing to a node with the // // parameterized value as item member and with // // NULL as the value of its next member. // node. Ptr Linked. List: : get. Node(element. Type elt) { node. Ptr temp = new node; if (temp != NULL) { temp->item = elt; temp->next = NULL; This private member function } generates a new node, loading it with return temp; the parameterized value for its item } member, and a NULL pointer for its next member. It returns a pointer to the new node to the calling function. Carrano - Chapter 4 CS 150 205

A Driver to Test the Linked List Class position = find. Bad. Word. Position(string.

A Driver to Test the Linked List Class position = find. Bad. Word. Position(string. List); if (position > 0) { cout << "How dare you mention MY name: " << string. List[position] << "!!!” << endl; while ((string. List. remove(BADWORD 1)) || (string. List. remove(BADWORD 2))); } // Driver program to test // // the Linked. List class. // #include <iostream> #include <fstream> #include <string> #include "linked. List. h" using namespace std; const string BADWORD 1 = "Bill"; const string BADWORD 2 = "White"; int find. Bad. Word. Position (Linked. List list); // The main function calls // inputs the list, and then // searches the list for two // "offensive" words, all // instances of which it // removes. void main() { Linked. List string. List; ifstream string. File; int position; return; } // // // string. File. open("letter. txt"); string. File >> string. List; cout << string. List << endl; Carrano - Chapter 4 cout << string. List << endl; // The find. Bad. Word. Position determines the // position of the earliest occurrence of // BADWORD 1 (if it's in the parameterized // Linked. List) or of BADWORD 2 (if it's not). // It returns zero if neither BADWORD occurs. int find. Bad. Word. Position(Linked. List list) { int pos = 0; int pos 1, pos 2; if (list. retrieve(BADWORD 1, pos 1)) pos = pos 1; else if (list. retrieve(BADWORD 2, pos 2)) pos = pos 2; return pos; } CS 150 // // // 206

Test Results Input File Resulting Execution Window Dear Contributor: Please send money. Please send

Test Results Input File Resulting Execution Window Dear Contributor: Please send money. Please send LOTS of money. Sincerely, Bill Clinton The White House Carrano - Chapter 4 CS 150 207

Modification: Outputting the List in the Original Order // The output operator outputs the

Modification: Outputting the List in the Original Order // The output operator outputs the values in the Linked. List, // // each on a separate output line in the parameterized // // output stream, starting with the tail element. // ostream& operator << (ostream &dest. File, const Linked. List &list) { list. backwards. Output(dest. File, list. head); return dest. File; } void Linked. List: : backwards. Output(ostream &output. File, node. Ptr ptr) const { if (ptr == NULL) return; else { backwards. Output(output. File, ptr->next); output. File << ptr->item << endl; } return; } The addition of this recursive, private member function permits the list to be output in reverse order (i. e. , in the order that it was input!). Carrano - Chapter 4 CS 150 208

Linked List Variation #1: Circular Linked Lists Head • The tail node points to

Linked List Variation #1: Circular Linked Lists Head • The tail node points to the head node, instead of to NULL. • Traversing the list can be done “fairly”: starting with the head node and moving the head pointer as the traversal progresses. • Useful approach for certain list applications, e. g. , cycling through active jobs in an operating system Carrano - Chapter 4 CS 150 209

Circular Linked Lists: What Changes Are Needed? • The list is empty if the

Circular Linked Lists: What Changes Are Needed? • The list is empty if the head points to NULL, but no active node ever has a NULL next pointer. • To traverse the list just once, set up a “current” pointer, initialized at the head; when the next pointer of “current” is the head, you’re at the tail. Head • Removing the head item requires that its predecessor be found and that the predecessor’s next pointer be updated. Carrano - Chapter 4 CS 150 210

Linked List Variation #2: Dummy Head Node dummy HEAD Rather than treating the first

Linked List Variation #2: Dummy Head Node dummy HEAD Rather than treating the first node as a special case, place a “dummy” node at the beginning of the list, and never remove it. • The list is empty if the dummy head node has a NULL next pointer. • Removing a node merely involves changing the predecessor’s next pointer to point to the successor. • Inserting a node merely involves setting the new node’s next pointer to the predecessor’s next pointer, and setting the predecessor’s next pointer to be the address of the new node. Carrano - Chapter 4 CS 150 211

Linked List Variation #3: Doubly Linked Lists HEAD Every node maintains two pointers, one

Linked List Variation #3: Doubly Linked Lists HEAD Every node maintains two pointers, one to its successor (the next pointer) and one to its predecessor (the previous pointer). This eliminates the need to keep track of preceding nodes during a traversal of the list. • The list is empty if the head pointer is NULL. • Removing a node requires changing the predecessor’s next pointer to point to the node’s successor and the successor’s previous pointer to point to the predecessor. Special cases involve removal of the first or the last node. • Inserting a node requires setting the new node’s next pointer to the successor, the new node’s previous pointer to the predecessor, and both the predecessor’s next pointer and the successor’s previous pointer to the address of the new node. Carrano - Chapter 4 CS 150 212

More Advanced Linked List Variations Front Top Rear QUEUE All insertions occur at one

More Advanced Linked List Variations Front Top Rear QUEUE All insertions occur at one end (the “rear”): all removals occur at the other end (the “front”) BINARY TREE Every node has two pointers, pointing to left and right “offspring” Root STACK All insertions and removals take place from the same end: the “top” of the stack Carrano - Chapter 4 CS 150 213