Problems with Linked List (as we’ve seen so far…) We can insert a node only after a node we have a pointer to. We can remove a node only if we have a pointer to its predecessor node We can traverse the list in only the forward direction Solution?
Stack Linked list or array?? Subset of list Only 2 operations: push() and pop() Stick something on the end of the stack, or take something off the end of the stack Last-in, first-out (LIFO) Think of a pile of … almost anything at all … you can’t take anything off the BOTTOM of the pile, only off the top. Equally, you can’t add to the pile at the bottom, only at the top. Applications: Reversing a word The “undo” option Backgracking in a maze Memory for functions (the easiest way to visualize this is recursion) Linked list or array?? Hint: oh please…
Pop() How do we implement pop? How many steps? Now pop again… Where is the last pointer still pointing? Is there a better way? (More than one…) What about arrays – will that work better? last 7 4 3 8 first NULL
Doubly-linked list: pop() class DNode { friend class LL; int data; DNode *next; DNode *prev; int size; public: DNode(int x); ~DNode(); }; //DNode Now what do we need to do? DNode *temp = last; last = last->prev; delete temp; last->next = NULL; size--; Now how many steps? last first NULL 7 4 3 8 NULL NULL temp Made it to here
Inserting 6 into the ordered list: temp last first 2 4 7 8 NULL NULL NULL 6 NULL n DNode *temp = first; while (temp->data < 6) { // left out check for end of list temp = temp->next; } DNode *n = new DNode(6); n->prev = temp->prev; temp->prev->next = n; n->next = temp; temp->prev = n; size ++; Easier with a doubly-linked list?
bool LL::delete(int x) { DNode. tmp; for (tmp = first; tmp bool LL::delete(int x) { DNode *tmp; for (tmp = first; tmp != NULL; tmp = tmp->next) { if (tmp->data== x) { if (tmp->prev== NULL) { first = tmp->next; } else if(tmp->next== NULL) { tmp->prev->next = NULL; else { /* Remove from middle */ tmp->prev->next=tmp->next; /* Fix previous node's next to skip over the removed node. */ tmp->next->prev = tmp->prev; /* Fix next node's prev to skip over the removed node. */ delete tmp; return true; return false;
Doubly-linked list: Disadvantages: Advantages: A bit more memory (now we’ve got that prev pointer space for each node) Must manage more pointers when performing operations on the linked list (e.g., insert, remove, etc.) FOR EVERY CHANGE IN LIST: we must manage both the next AND the prev pointer Advantages: Makes pop() easier (O(1)) Makes inserting in ordered lists, and inserting at index 1 a bit easier Makes traversing the list in reverse order easier Reversing the list is easy now Can go backwards and forwards from a node in a list We may need surrounding nodes We may need data that occurred “close to” a node with certain data
How about Find in a linked list? first last 7 4 3 8 NULL Find 3 in the list Find 6 in the list O(n) Is there a better way? Binary search tree!
Tree (new ADT) Terminology: A tree is a collection of elements (nodes) Each node may have 0 or more successors (called children) How many does a list have? Each node has exactly one predecessor (called the parent) Except the starting node, called the root Links from node to its successors are called branches Nodes with same parent are siblings Nodes with no children are called leaves
Tree We also use words like ancestor and descendent Pets is the parent of Dogs and Cats Poodle and Beagle are the children of Dogs Poodle, Beagle, Persian, and Siamese are descendents of Pets, Pets is the ancestor of Poodle, Beagle, Persian, and Siamese
Tree Terminology Subtree of a node: Depth of a node: 1 2 3 4 A tree whose root is a child of that node Depth of a node: A measure of its distance from the root: Depth of the root = 0 Depth of other nodes = 1 + depth of parent 1 2 3 4
Fullness and Completeness: Trees grow from the top down New values inserted in new leaf nodes In a full tree, every node has 0 or 2 non-null children A complete tree of height h is filled up to depth h-1, and, at depth h, any unfilled nodes are on the right.