1 / 41

Linked List Containers

This example demonstrates how to concatenate two linked lists. It provides both an easy-to-implement version and a safer version that returns a new linked list.

janadavis
Download Presentation

Linked List Containers

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. Linked List Containers

  2. Concatenate Example • Concatenate(LinkedList<Type> listB): Add all of the elements of a second list to the end of the first list • Three cases: • ListA is empty – Set head for listA to head of listB • ListB is empty – No change, nothing to do • Both have data – Set pointer on last node of listA to head for listB • This version of concatenate is: • Easy to implement • Destructive towards listsA and listB – as it potentially changes how listA and listB work from here on out (listA delete will now cause listB nodes to go away as well)

  3. Concatenate Example void LinkedList<Type>::concatenate(const LinkedList<Type> & listB) { // empty list A if (!first) { first = listB.first; return; } else if (listB.first) // if b is empty do nothing { // get to end of my list (listA) ListNode<Type>* current = first; while (current->link != 0) { current = current->link; } current->link = listB.first; } }

  4. Safer Concatenate Example LinkedList& LinkedList<Type>::concatenate(const LinkedList<Type> & listB) { // make a copy of list A using copy constructor LinkedList returnList = *(new LinkedList(*this)); if (listB.first) // if b is empty do nothing, else add to end { ListNode<Type>* current =listB.first; while (current->link != 0) { listA.add(current->value); current = current->link; } return returnList; } } This version returns a new LinkedList which is a copy of listA with copies of listB nodes added to the end. Changes to the new list don’t affect listA or listB.

  5. Useful Linked List Add-Ons • Are there new variables/changes to the lists as they have been defined that could make our jobs as programmers easier? • Size member variable • Be able to determine current size of list, bound positions for add, delete, etc. • Maintaining a variable is cheap, counting the nodes every time size is called (the alternative) is not! • Tail pointer • Significantly simplifies addition at end of list

  6. Tail Pointers • If doing a lot of adds to the end (which is natural), a tail pointer provides instant access to the last node • Does require some extra overhead in the add/delete functions to keep tail updated • List Construction: first=tail=0; 1-node: first != 0 and first == tail first tail List1 Data1 List1 Data2 List1 Data3

  7. Circular Lists • Another improvement on LinkedLists: • Use link pointer of last node to point to the first node. • Changes to implementation: • Check to see if at last node: test “if (current -> link == first)” instead of “if (current->link == 0)” • Insertion and deletion need to preserve property that last nodes link is always set equal to first

  8. Circular List Implementation Retrofitting our LinkedList to make circular: • Don’t want to have just a head pointer: Why? • If inserting at tail, have to traverse the whole list from head to get to tail to update the tails link • If inserting at head, need to find last node to point its link to new head - this also traverses the whole list • Circular linked lists are much more efficient if use tail (last) pointer as the pointer for the list. • Two pointers (head and tail) are actually overkill .. why?

  9. Circular Linked Lists first tail List1 Data1 List1 Data2 List1 Data3 Can access head via tail->link in one step so don’t need head pointer

  10. Circular Linked List void insertAtFront(ListNode <Type> *x) { if (tail == 0) { // empty list, tail = x; x-> link = x; // point to yourself } else { x->link = tail->link; // point new head link to old head tail->link = x; // point tail to new head } } insertAtRear() only requires adding tail = x in the else statement (to update rear to new node)

  11. Linked List Examples • Now that the basic structures of LinkedLists have been defined, what are some potential applications? • Target problems where can take advantage of LinkedList memory usage model • Target problems where can take advantage of dynamic aspects of LinkedList

  12. Linked List Example • Polynomials • Interested in representing and manipulating polynomials • Polynomial defined as: • Y = coef_n * xexp_n +coef_n-1 * xexp_n-1 + … coef_0 * x0 • Examples: 3x14 + 2x8 + 1 8x14 – 3x10 + 10x6

  13. Polynomials • Has a very nice linked representation • In particular, able to take advantage of sparse number of coefficients with a linked representation • Compare against an array that holds the coefficients and exponents for all possible indices from 0 to max degree • Horribly wasteful in terms of space • What if we had an array of Term objects, where a Term was an exponent/coefficient • Only need enough array space to hold true terms, so amount of space required ok.. However, we’ll see this is still inflexible.

  14. Polynomials • For each component of the polynomial, need to store coefficient and exponent struct Term { int coef; int exp; void Init(int c, int e) { coef = c; exp = e;} };

  15. Polynomials • Polynomial itself implemented by a templated LinkedList of Terms class Polynomial { private: LinkedList<Term> poly; };

  16. Polynomials • Adding Polynomials: 3x3 + 2x + 1 + 2x3 + 3x2 + 5 ================= 5x3 + 3x2 + 2x + 6

  17. Polynomials • Adding Polynomials: • Iterate through both lists • If exponent1 == exponent2, • CoefficientSum = Coefficient1 + Coefficient2 • If CoefficentSum != 0, add term to new polynomial representing answer • Else, • Find higher exponent • Add term to new polynomial representing answer

  18. 3 3 2 1 1 0 2 3 3 2 5 0 5 3 3 2 2 1 6 0 Polynomials

  19. Polynomials • The “Answer” polynomial is where LinkedLists have another win. There is now way beforehand to know how may terms there will be in the answer polynomial • Number of terms is anywhere from (the size of the largest list) to the size of the largest list plus the size of the smallest list) • With an array representation, would have to overallocate to handle large answers • With LinkedLists, just grab a new Node when need it.

  20. Polynomials • Overload + operator to perform polynomial addition • Implementation in page 193

  21. Example: Equivalence Classes • Another Example of Linked List Usage: Finding Equivalence Classes • Definition: Given a relation (<, >, ==, …), the relation is an equivalence relation over a set S if the relation is reflexive, symmetric, and transitive over S

  22. Equivalence Relations • Reflexive A ? A Is < Reflexive? A < A No Is = Reflexive? A == A Yes • Symmetric: If A ? B, then B ? A Is < Symmetric? A < B, then B < A No Is = Symmetric? A = B, then B = A Yes

  23. Equivalence Relations • Transitive If A ? B and B ? C, then A ? C Is < transitive? A < B, B < C, A < C Yes Is = transitive? A = B, B = C, A = C Yes = is reflexive, symmetric, and transitive, so it is an equivalence relation < fails on reflexive and symmetric, so it is not an equivalence relation

  24. Equivalence Classes • Effect of equivalence relations is the ability to partition a set S into classes such that any two members of S, x and y, are in the same class if x equiv y. • Classes are called equivalence classes

  25. Equivalence Classes Equivalence Class Example: Let our relationship be = mod 3 Reflexive 5 mod 3 = 5 mod 3 => 2 = 2 Yes Symmetric 5 mod 3 = 8 mod 3, then 8 mod 3 = 5 mod 3 2 = 2, then 2 = 2 Yes Transitive 5 mod 3 = 8 mod 3, 8 mod 3 = 14 mod 3, then 5 mod 3 = 14 mod 3 2 = 2, 2 = 2, then 2 = 2, Yes

  26. Equivalence Classes • Equivalence Classes: • All numbers that are = mod 3 are in the same equivalence class Mod 3 = 0 Mod 3 = 1 Mod 3 = 2 {0,3,6,9,…} {1,4,7,10,…} {2,5,8,11,…}

  27. Equivalence Classes • Goal: • Given a list of equivalence relations between items x and y, construct the equivalence classes Relations: 0 = 4, 3 = 1, 6 = 10, 8 = 9, 7 = 4, 6 = 8, 3 = 5, 2= 11, 11 = 0 Classes: {0,2,4,7,11}, {1,3,5,}, {6,8,9,10}

  28. Equivalence Classes • Could build N by N (N = number of total items) matrix indicating relationship, but most of entries are likely to be zero • Instead, use an array of pointers for 1-dimensional list of all items, where for each item, the pointer points to a list of all items that are equivalent in the input • For each item I = J input, Add J to I’s list Add I to J’s list

  29. 3 4 11 9 11 5 7 1 0 2 8 4 6 8 6 3 0 10 Equivalence Classes 0 1 2 3 4 5 6 7 8 9 10 11

  30. Equivalence Classes • To find equivalence classes, • Start at front of array • Print X, Mark as printed • Print all things equivalent to X (follow its list), mark as printed • For each thing equivalent to X, print the appropriate list

  31. Equivalence Classes • Include an array to indicate whether that data has already been written: boolean out[n] initially all set to false • Code on pages 205, 206 of book

  32. Equivalence Classes • First Steps of Test Run on Previous Data

  33. Complexity of Equivalence Class Operations • Initialization Initializing sequence and output arrays with n possible values: O(n) Processing each pair of input – 2 steps * m inputs: O(m) So, pre-processing requires: O(n+m) • Traversing list: n possible lists to look at, 2m entries total on the lists Only process list if haven’t already written So only looks at each entry in the array once (upper bound of n) Since only looks at each array once, only looks at nodes underneath the array entry once (upper bound of 2m) So traverse time is O(n+m)

  34. Doubly Linked Lists • Biggest problem with linked lists as we’ve used so far: • Can only navigate in one direction • Requires traversals from front to a position, even if currently located right behind where want to be • Requires “trailing pointer” if want to easily get access to previous node for current node • When update current to current->next, update prev to current

  35. Doubly Linked Lists • Work around these issues by storing both the left and right side neighbors of a linked list • Makes add, delete, and other array manipulation operators more complicated as have to preserve doubly linked property

  36. Doubly Linked Lists • Definition: class DblList; // forward declaration class DblListNode { friend class DblList; private: int data; DblListNode *right, *left; };

  37. Doubly Linked Lists class DblList { public: // list manipulation private: DblListNode* first; };

  38. LEFT LEFT LEFT LEFT DATA 10 15 29 RIGHT RIGHT RIGHT RIGHT Doubly Linked Lists Example Node 3 Node Circular Doubly Linked List

  39. Doubly Linked List • Note that, given a pointer p, p = p->left->right = p->right->left • Going back and forth is equally easy.

  40. L L L 10 12 11 R R Doubly Linked List void DblList::Insert(DblListNode *new, DblListNode *current) { // insert new after x new->left = current; new->right = current->right; current->right->left = new; current->right = new; } new current R

  41. L L L 10 12 11 R R Doubly Linked List void DblList::Delete(DblListNode *toDelete) { // delete node pointed to by toDelete toDelete->left->right = toDelete->right; toDelete->right->left = toDelete->left; delete toDelete; } toDelete

More Related