1 / 21

Array vs. Linked List Comparison in Programming

Explore the benefits and drawbacks of arrays and linked lists in programming, covering aspects such as memory allocation, access methods, and data manipulation techniques. Dive into class definitions and implementations for linked lists.

crystalf
Download Presentation

Array vs. Linked List Comparison in Programming

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. 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. CS 150

  2. Location of first list item Data element Location of next item Data element NULL indicator of last element Data element Location of next item Data element Location of next item Data element Location of next item Data element Location of next item Linked Lists CS 150

  3. Before: After: 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. CS 150

  4. Before: After: Linked List Advantages (Continued) • Removing an element from the linked list merely requires linking the node’s predecessor to its successor. 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. CS 150

  5. A Linked List Class Definition in C++ // Class definition file: linkedList.h // #ifndef LINKED_LIST_H #include <string> using namespace std; typedef string elementType; struct node; typedef node* nodePtr; struct node { elementType item; nodePtr next; }; class LinkedList { public: // Constructors and destructor LinkedList(); LinkedList(const LinkedList &list); ~LinkedList(); // Member functions int size(); bool insert(elementType elt); bool remove(elementType elt); bool retrieve(elementType elt, int &position); elementType& operator [ ] (int position); LinkedList& operator = (const LinkedList &list); friend istream& operator >> (istream &sourceFile, LinkedList &list); friend ostream& operator << (ostream &destFile, const LinkedList &list); private: // Data member nodePtr head; // Member function nodePtr getNode(elementType elt); }; #define LINKED_LIST_H #endif Note that the mutual dependence between the definitions of the node struct and the nodePtr type requires that their definitions be handled “creatively”. CS 150

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

  7. The Linked List Class Implementation (Continued) // The assignment operator makes the current // object a copy of the parameterized object LinkedList& LinkedList::operator = (const LinkedList &list) { nodePtr currPtr, thisCurrPtr, thisPrevPtr; if(head == list.head) return *this; (*this).~LinkedList(); if (list.head == NULL) head = NULL; else { head = getNode(list.head->item); thisPrevPtr = head; currPtr = list.head->next; while (currPtr != NULL) { thisCurrPtr = getNode(currPtr->item); thisPrevPtr->next = thisCurrPtr; thisPrevPtr = thisCurrPtr; currPtr = currPtr->next; } } return *this; } Make sure that the user is not assigning the list to itself. The destructor must delete every node in the old list, ensuring that no unwanted nodes remain in memory. CS 150

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

  9. 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 LinkedList. // // A boolean value indicating whether the // // insertion worked is returned. // bool LinkedList::insert(elementType elt) { nodePtr insertPtr = getNode(elt); if (insertPtr == NULL) return false; if (head == NULL) head = insertPtr; else { insertPtr->next = head; head = insertPtr; } return true; } If the getNode 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. CS 150

  10. The Linked List Class Implementation (Continued) // The remove member function locates the first occurrence of the parameterized // // value in the LinkedList and detaches it from the LinkedList. A boolean // // value indicating whether the removal worked is returned. // bool LinkedList::remove(elementType elt) { nodePtr currPtr = head; nodePtr prevPtr = NULL; bool foundIt = false; while ((!foundIt) && (currPtr != NULL)) { if (currPtr->item == elt) foundIt = true; else { prevPtr = currPtr; currPtr = currPtr->next; } } if (foundIt) { if (prevPtr == NULL) head = currPtr->next; else prevPtr->next = currPtr->next; delete currPtr; } return foundIt; } Loop through the list, keeping track of the node being tested (to see if its value is elt) and its predecessor in the list. If the sought value is in the head node, then the list needs a new head. If the sought value is in a non-head 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

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

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

  13. The Linked List Class Implementation (Continued) // The getNode member function creates and returns // // a new nodePtr, pointing to a node with the // // parameterized value as its item member and with // // NULL as the value of its next member. // nodePtr LinkedList::getNode(elementType elt) { nodePtr temp = new node; if (temp != NULL) { temp->item = elt; temp->next = NULL; } return temp; } This private member function generates a new node, loading it with 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. CS 150

  14. A Driver to Test the Linked List Class // Driver program to test // // the LinkedList class. // #include <iostream> #include <fstream> #include <string> #include "linkedList.h" using namespace std; const string BADWORD1 = "Bill"; const string BADWORD2 = "White"; int findBadWordPosition (LinkedList 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() { LinkedList stringList; ifstream stringFile; int position; stringFile.open("letter.txt"); stringFile >> stringList; cout << stringList << endl; position = findBadWordPosition(stringList); if (position > 0) { cout << "How dare you mention MY name: " << stringList[position] << "!!!” << endl; while ((stringList.remove(BADWORD1)) || (stringList.remove(BADWORD2))); } cout << stringList << endl; return; } // The findBadWordPosition determines the // // position of the earliest occurrence of // // BADWORD1 (if it's in the parameterized // // LinkedList) or of BADWORD2 (if it's not). // // It returns zero if neither BADWORD occurs. // int findBadWordPosition(LinkedList list) { int pos = 0; int pos1, pos2; if (list.retrieve(BADWORD1, pos1)) pos = pos1; else if (list.retrieve(BADWORD2, pos2)) pos = pos2; return pos; } CS 150

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

  16. Modification: Outputting the List in the Original Order // The output operator outputs the values in the LinkedList, // // each on a separate output line in the parameterized // // output stream, starting with the tail element. // ostream& operator << (ostream &destFile, const LinkedList &list) { list.backwardsOutput(destFile, list.head); return destFile; } void LinkedList::backwardsOutput(ostream &outputFile, nodePtr ptr) const { if (ptr == NULL) return; else { backwardsOutput(outputFile, ptr->next); outputFile << 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!). CS 150

  17. Head Linked List Variation #1: Circular Linked Lists • 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 CS 150

  18. Head 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. • Removing the head item requires that its predecessor be found and that the predecessor’s next pointer be updated. CS 150

  19. dummy HEAD Linked List Variation #2: Dummy Head Node • 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. CS 150

  20. HEAD Linked List Variation #3: Doubly Linked Lists • 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. CS 150

  21. Top Front Rear Root More Advanced Linked List Variations 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” STACK All insertions and removals take place from the same end: the “top” of the stack CS 150

More Related