Variations on Linked Lists Ellen Walker CPSC 201 Data Structures Hiram College.

23
Variations on Linked Lists Ellen Walker CPSC 201 Data Structures Hiram College

Transcript of Variations on Linked Lists Ellen Walker CPSC 201 Data Structures Hiram College.

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)

BarryAnn

Carol

Ellen

/* 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){

}