230 likes | 392 Views
Variations on Linked Lists. Ellen Walker CPSC 201 Data Structures Hiram College. Linked List (review). Each element contains two parts: Value of this element Pointer to the next element class string_node { Private: string val; string_node *next; }.
E N D
Variations on Linked Lists Ellen Walker CPSC 201 Data Structures Hiram College
Linked List (review) • Each element contains two parts: • Value of this element • Pointer to the next element class string_node { Private: string val; string_node *next; }
Inserting into a Linked List (Review) /* Assume item is a reference to the node that contains “Barry”*/ Node<string> newNode = new Node<string> (“Carol”); newNode.next = aNode.next; aNode.next = newitem;
Printing a Linked List (Review) //print elements, starting at the node called head; // Uses a for loop for(Node<String> current=head; current!=null; current=current.next){ System.out.println(current.data); }
Printing Using Iterator (Review) //prints the list, one item per line //returns iterator pointing before the list… Iterator<String> itr = aList.iterator(); while(itr.hasNext()){ String name = itr.next(); System.out.println(name); }
LinkedList Implementation (Review) public class LinkedList<E>{ private Node<E> head; //first element or null private int size; //list length … private static class Node<E>{ //inner class private E data; private node<E> next; } //methods go here }
Implementing toString • Writes elements of list into a string • Use either traversal from before (iterator version shown) String toString(){ StringBuilder result = new StringBuilder(); Iterator<E> itr = iterator(); while(itr.hasNext()){ result.append(itr.next()); result.append(‘\n’); } }
Dummy Nodes simplify implementation • An empty list has one node (the dummy node) • There is no longer a special case for adding the first element of the node! • What changes need to be made to… • Constructor? • Find / Retrieve ? • Insert / Delete? • Sometimes a dummy node can have a useful value (e.g. smallest possible element for sorted list)
Changes to the implementation for a dummy node • Constructor • Head is a new (dummy) node instead of NULL • indexOf / get • indexOf is unchanged (assume value not otherwise in list) • get(k) will return value at node (k+1) • Insert / Delete • Begin by locating the predecessor node • No special cases for first node (it has a predecessor)
Circular List • Circular List: The tail of the list points back to the head • There is no NULL pointer to “end” the list.
Issues with circular list • How do you know when you’re done? • Make sure you save the head pointer. • When (cur.next == head) you’ve reached the end • How are insertion and deletion handled? • No special cases! • Predecessor to head node is the last node in the list.
The Josephus Problem • (One of many variations…) The founder of a startup is forced to lay off all but one employee. Not having any better way to decide, he arranges all employees in a circle and has them count off. The 10th employee in the circle is laid off, and the count begins again. The last person is not laid off. • If there are N employees, where should you sit to avoid being laid off?
Solution • Model the circle of employees as a circular linked list • Implement the counting off process, and delete the 10th employee each time • After N-1 people are deleted, there should be only one employee left. • That employee’s original position number is the solution to the problem.
Doubly Linked List • Each node has prev and next pointer • List can be traversed forward or backward • To insert a node after “cur” • Node<E> tmp = new Node<E>(newItem); • tmp.next = cur.next; • cur.next=tmp; • tmp.prev=cur; • tmp.next.prev = tmp; • Reverse the process to delete!
Which list implementation? • Array • Can jump into the middle easily (random access) • Inserting & deleting can require time-consuming shifting • Must allocate block of memory at once (can resize later with new) • Linked • No random access • Insert & delete are fixed cost, once you decide where. • Nodes allocated one at a time.
Linked List Choices • Plain vanilla • Simple, small • Dummy header • Eliminates special cases (chance for error) • Circular • No defined start position in sequence • Can find the node before, though it takes N steps • Doubly linked • Easy to find the node before • Larger Node; twice as many special cases • Circular and doubly linked
Linked Lists and Recursion • Recursive definition of a list • Null (empty list) is a list (base case) • A list consists of one item (the head) followed by a list (next) • Example: • A->B->C-| is a list • Head = A, next = B->C-|
Recursive Function on Lists • Base case for the recursive function is the empty list (base case for the definition) • Other cases - • “Take a step” = do something to the head • Recurse = call function for the rest of the list • May or may not build up a solution
Recursive List Search Node<E> recFind (Node<E> head, E x){ //x is not in an empty list! If (head == null) return null; //x is found at the beginning Else if (head.item == x) return head; //Recursive case: search the rest of the list Return recFind(head.next, x); }
Recursive functions are private! • A recursive function uses Node references. • Node references are private • Implementation detail • Not every implementation of List has Nodes • Most recursive functions have a public “starter” and a private internal function
Public Caller for recFind boolean isIn(E x){ //call Find on the head of the list //if Find does not return null, the item is in // the list. return (recFind(head,x) != null); }
Recursive CountItem • This function counts the number of occurrences of the item x in the list Int CountItem (Node * head, ItemType x){ }
Public Caller for CountItem int List::howMany(ListItemType x){ }