Head + tail if ( ... ) { // base case calculate results } else { - - PowerPoint PPT Presentation

head tail
SMART_READER_LITE
LIVE PREVIEW

Head + tail if ( ... ) { // base case calculate results } else { - - PowerPoint PPT Presentation

ITI 1121. Introduction to Computing II Marcel Turcotte School of Information Technology and Engineering Version of March 26, 2011 Abstract Recursive list processing (part II) These lecture notes are meant to be looked at on a


slide-1
SLIDE 1

ITI 1121. Introduction to Computing II ∗

Marcel Turcotte School of Information Technology and Engineering Version of March 26, 2011 Abstract

  • Recursive list processing (part II)

∗These lecture notes are meant to be looked at on a computer screen. Do not print them unless it is necessary.

slide-2
SLIDE 2

“Head + tail”

if ( ... ) { // base case calculate results } else { // general case // pre-processing s = method( p.next ); // recursion // post-processing }

slide-3
SLIDE 3

E get( int index )

Let’s build the recursive method, this requires augmenting the signature of the method E get( int index ) with an additional parameter representing the current element (p).

slide-4
SLIDE 4

E get( int index )

Let’s build the recursive method, this requires augmenting the signature of the method E get( int index ) with an additional parameter representing the current element (p). private E get( Node<E> p, int index );

slide-5
SLIDE 5

E get( int index )

Let’s build the recursive method, this requires augmenting the signature of the method E get( int index ) with an additional parameter representing the current element (p). private E get( Node<E> p, int index ); If index represents the position of the element with respect to the list starting at p, what is the position of the element in the list starting at p.next?

slide-6
SLIDE 6

E get( int index )

Let’s build the recursive method, this requires augmenting the signature of the method E get( int index ) with an additional parameter representing the current element (p). private E get( Node<E> p, int index ); If index represents the position of the element with respect to the list starting at p, what is the position of the element in the list starting at p.next? Yes, it’s index-1!

slide-7
SLIDE 7

E get( int index )

Let’s build the recursive method, this requires augmenting the signature of the method E get( int index ) with an additional parameter representing the current element (p). private E get( Node<E> p, int index ); If index represents the position of the element with respect to the list starting at p, what is the position of the element in the list starting at p.next? Yes, it’s index-1! What is the base case?

slide-8
SLIDE 8

E get( int index )

Let’s build the recursive method, this requires augmenting the signature of the method E get( int index ) with an additional parameter representing the current element (p). private E get( Node<E> p, int index ); If index represents the position of the element with respect to the list starting at p, what is the position of the element in the list starting at p.next? Yes, it’s index-1! What is the base case? If the index is zero then simply returns p.value.

slide-9
SLIDE 9

private E get( Node<E> p, int index )

private E get( Node<E> p, int index ) { if ( index == 0 ) { return p.value; } return get( p.next, index-1 ); }

slide-10
SLIDE 10

private E get( Node<E> p, int index )

private E get( Node<E> p, int index ) { if ( index == 0 ) { return p.value; } return get( p.next, index-1 ); } What would occur if the initial value of index was larger than the total number

  • f elements in list?
slide-11
SLIDE 11

private E get( Node<E> p, int index )

private E get( Node<E> p, int index ) { if ( index == 0 ) { return p.value; } return get( p.next, index-1 ); } What would occur if the initial value of index was larger than the total number

  • f elements in list? index > 0 and p == null.
slide-12
SLIDE 12

private E get( Node<E> p, int index )

private E get( Node<E> p, int index ) { if ( p == null ) { throw new IndexOutOfBoundsException(); } if ( index == 0 ) { return p.value; } return get( p.next, index - 1 ); }

slide-13
SLIDE 13

public E get( int index )

public E get( int index ) { if ( index < 0 ) { throw new IndexOutOfBoundsException(); } return get( first, index ); } private E get( Node<E> p, int index ) { if ( p == null ) { throw new IndexOutOfBoundsException(); } if ( index == 0 ) { return p.value; } return get( p.next, index-1 ); }

slide-14
SLIDE 14

int indexOf( E obj )

The methods indexOf returns the position of the first (left most) occurrence of

  • bj in the list, the first element of the list is the position 0, the method returns
  • 1 if the element is not found in the list.
slide-15
SLIDE 15

int indexOf( E obj )

The methods indexOf returns the position of the first (left most) occurrence of

  • bj in the list, the first element of the list is the position 0, the method returns
  • 1 if the element is not found in the list.

Following the “head + tail” strategy, the general case will involve a recursive call for the tail of the list: int s = indexOf( p.next, o );

slide-16
SLIDE 16

int indexOf( E obj )

The methods indexOf returns the position of the first (left most) occurrence of

  • bj in the list, the first element of the list is the position 0, the method returns
  • 1 if the element is not found in the list.

Following the “head + tail” strategy, the general case will involve a recursive call for the tail of the list: int s = indexOf( p.next, o ); What does s represent?

slide-17
SLIDE 17

int indexOf( E obj )

The methods indexOf returns the position of the first (left most) occurrence of

  • bj in the list, the first element of the list is the position 0, the method returns
  • 1 if the element is not found in the list.

Following the “head + tail” strategy, the general case will involve a recursive call for the tail of the list: int s = indexOf( p.next, o ); What does s represent? It’s the position of o in the list starting at p.next.

slide-18
SLIDE 18

int indexOf( E obj )

The methods indexOf returns the position of the first (left most) occurrence of

  • bj in the list, the first element of the list is the position 0, the method returns
  • 1 if the element is not found in the list.

Following the “head + tail” strategy, the general case will involve a recursive call for the tail of the list: int s = indexOf( p.next, o ); What does s represent? It’s the position of o in the list starting at p.next. What is the position of o with respect to the list starting at p?

slide-19
SLIDE 19

int indexOf( E obj )

The methods indexOf returns the position of the first (left most) occurrence of

  • bj in the list, the first element of the list is the position 0, the method returns
  • 1 if the element is not found in the list.

Following the “head + tail” strategy, the general case will involve a recursive call for the tail of the list: int s = indexOf( p.next, o ); What does s represent? It’s the position of o in the list starting at p.next. What is the position of o with respect to the list starting at p? 1 + s.

slide-20
SLIDE 20

int indexOf( Node<E> p, E obj )

slide-21
SLIDE 21

int indexOf( Node<E> p, E obj )

Combining s (the result of the recursive call) and the current node.

slide-22
SLIDE 22

int indexOf( Node<E> p, E obj )

Combining s (the result of the recursive call) and the current node. if ( p.value.equals( o ) ) { result = 0; } else if ( result == -1 ) { result = s; } else { result = 1 + s; }

slide-23
SLIDE 23

int indexOf( Node<E> p, E obj )

What is the base case?

slide-24
SLIDE 24

int indexOf( Node<E> p, E obj )

What is the base case? The smallest list is the empty list, it does not contain the value we’re looking for, we should return the special value -1, to indicate that a match could not be found.

slide-25
SLIDE 25

int indexOf( Node<E> p, E obj )

What is the base case? The smallest list is the empty list, it does not contain the value we’re looking for, we should return the special value -1, to indicate that a match could not be found. if ( p == null ) { return -1; }

slide-26
SLIDE 26

int indexOf( Node<E> p, E obj )

private int indexOf( Node<E> p, E o ) { if ( p == null ) { return -1; } int result = indexOf( p.next, o); if ( p.value.equals( o ) ) { return 0; } if ( result == -1 ) { return result; } return result + 1; }

slide-27
SLIDE 27

int indexOf( Node<E> p, E obj )

Is this working?

slide-28
SLIDE 28

int indexOf( Node<E> p, E obj )

Is this working? Yes, but it’s inefficient.

slide-29
SLIDE 29

int indexOf( Node<E> p, E obj )

Is this working? Yes, but it’s inefficient. Why?

slide-30
SLIDE 30

int indexOf( Node<E> p, E obj )

The recursion should stop as soon as the first occurrence has been found.

slide-31
SLIDE 31

int indexOf( Node<E> p, E obj )

The recursion should stop as soon as the first occurrence has been found. Okay, but how?

slide-32
SLIDE 32

int indexOf( Node<E> p, E obj )

The recursion should stop as soon as the first occurrence has been found. Okay, but how?

private int indexOf( Node<E> p, E o ) { if ( p == null ) { // Base case return -1; } if ( p.value.equals( o ) ) { // Base case return 0; } // General case int result = indexOf( p.next, o ); if ( result == -1 ) { return result; } return result + 1; }

p.value.equals( o ) is a base case!

slide-33
SLIDE 33

int indexOf( Node<E> p, E obj )

Observe how “declarative” the method is.

private int indexOf( Node<E> p, E o ) { if ( p == null ) { // Base case return -1; } if ( p.value.equals( o ) ) { //Base case return 0; } // General case int result = indexOf( p.next, o ); if ( result == -1 ) { return result; } return result + 1; }

slide-34
SLIDE 34

int indexOfLast( E obj, Node<E> p )

The methods indexOfLast returns the position of the last (right most) occurrence

  • f obj in the list, the first element of the list is the position 0, the method returns
  • 1 if the element is not found in the list.
slide-35
SLIDE 35

int indexOfLast( E obj, Node<E> p )

The methods indexOfLast returns the position of the last (right most) occurrence

  • f obj in the list, the first element of the list is the position 0, the method returns
  • 1 if the element is not found in the list.

What are the necessary changes?

slide-36
SLIDE 36

int indexOfLast( E obj, Node<E> p )

The methods indexOfLast returns the position of the last (right most) occurrence

  • f obj in the list, the first element of the list is the position 0, the method returns
  • 1 if the element is not found in the list.

What are the necessary changes? First, can p.value.equals( o ) be a base case?

slide-37
SLIDE 37

int indexOfLast( E obj, Node<E> p )

The methods indexOfLast returns the position of the last (right most) occurrence

  • f obj in the list, the first element of the list is the position 0, the method returns
  • 1 if the element is not found in the list.

What are the necessary changes? First, can p.value.equals( o ) be a base case? No, the recursion must be allowed to go all the way to the end. Second, how to combine the result of indexOfLast(obj, p.next) and the current node?

slide-38
SLIDE 38

int indexOfLast( Node<E> p, E obj )

public int indexOfLast( E obj ) { return indexOfLast( first, obj ); } private int indexOfLast( Node<E> p, E obj ) { if (p == null) { return -1; } int result = indexOfLast( p.next, obj ); if ( result > -1 ) { return result + 1; } else if ( obj.equals( p.value ) ) { return 0; } else { return -1; } }

slide-39
SLIDE 39

boolean contains( E o )

The method contains returns true if the list contains the element o, i.e. there is a node such that value.equals( o ). The auxiliary will initiates the search from the first node. public boolean contains( E o ) { return contains( o, first ); }

slide-40
SLIDE 40

boolean contains( Node<E> p, E o )

The signature of the recursive methods will be: private boolean contains( Node<E> p, E o ); Let’s apply the head and tail strategy. The empty list has to be part of the base case, if list is empty it cannot contain the object, contains should return false: if ( p == null ) { return false; } The strategy suggests calling contains for the tail: boolean result = contains( o, p.next );

slide-41
SLIDE 41

boolean contains( E o )

Contains is similar to indexOf, the method should stop as soon as the first

  • ccurrence has been found.

private boolean contains( Node<E> p, E o ) { if ( p == null ) { return false; } if ( p.value.equals( o ) ) { return true; } return contains( o, p.next ); }

slide-42
SLIDE 42

More complex patterns

The methods considered this far used one element at a time but this does not need to be.

slide-43
SLIDE 43

More complex patterns

The methods considered this far used one element at a time but this does not need to be. Let’s consider the method isIncreasing. It returns true if each element of the list is equal to or greater than its predecessor, and false otherwise.

slide-44
SLIDE 44

More complex patterns

The methods considered this far used one element at a time but this does not need to be. Let’s consider the method isIncreasing. It returns true if each element of the list is equal to or greater than its predecessor, and false otherwise. To solve this problem, let’s scan the list and return false as soon a consecutive pair of elements has been found such that the predecessor is greater than its successor, if the end is reached this means the list is increasing.

slide-45
SLIDE 45

boolean isIncreasing()

public boolean isIncreasing() { return isIncreasing( first ); }

slide-46
SLIDE 46

boolean isIncreasing( Node<E> p )

Base case(s): shortest valid list(s)?

slide-47
SLIDE 47

boolean isIncreasing( Node<E> p )

Base case(s): shortest valid list(s)? The empty list and the singleton list are valid and increasing.

slide-48
SLIDE 48

boolean isIncreasing( Node<E> p )

Base case(s): shortest valid list(s)? The empty list and the singleton list are valid and increasing. if ( ( p == null ) || ( p.next == null ) ) { return true; }

slide-49
SLIDE 49

boolean isIncreasing( Node<E> p )

General case: 1) should the strategy be to make a recursive call the combine this result or 2) consider the current element(s) then make a recursive call (if necessary)?

slide-50
SLIDE 50

boolean isIncreasing( Node<E> p )

General case: 1) should the strategy be to make a recursive call the combine this result or 2) consider the current element(s) then make a recursive call (if necessary)? if ( p.value.compareTo( p.next.value ) > 0) { return false; } else { return isIncreasing( p.next ); }

slide-51
SLIDE 51

boolean isIncreasing( Node<E> p )

private boolean isIncreasing( Node<E> p ) { if ( ( p == null ) || ( p.next == null ) ) { return true; } if ( p.value.compareTo( p.next.value ) > 0 ) { return false; } return isIncreasing( p.next ); }

slide-52
SLIDE 52

Pitfall!

private boolean isIncreasing( Node<E> p ) { if ( ( p == null ) || ( p.next == null ) ) { return true; } if ( p.value.compareTo( p.next.value ) > 0 ) { return false; } return isIncreasing( p.next.next ); }

slide-53
SLIDE 53

Exercises

For a singly linked list implement the following methods recursively. void addLast( E o ); adds an element at the last position of a list. boolean eq( OrderedList<E> other ); compares all the elements of this list to the elements of the other list; the lists are not necessarily of the same length!

slide-54
SLIDE 54

Modifying the structure of the list

We now consider methods that are modifying the structure of the list.

slide-55
SLIDE 55

Modifying the structure of the list

We now consider methods that are modifying the structure of the list. For methods such as indexOf and contains, the consequence of unnecessary recursive calls was inefficiency.

slide-56
SLIDE 56

Modifying the structure of the list

We now consider methods that are modifying the structure of the list. For methods such as indexOf and contains, the consequence of unnecessary recursive calls was inefficiency. However, when the methods are allowed to change the structure of the list, such as remove below, the consequences of unnecessary recursive calls are severe.

slide-57
SLIDE 57

public void remove( E o )

void remove( E o ); removes the first (left most) occurrence of an object.

slide-58
SLIDE 58

public void remove( E o )

void remove( E o ); removes the first (left most) occurrence of an object. Outline a general strategy.

slide-59
SLIDE 59

public void remove( E o )

void remove( E o ); removes the first (left most) occurrence of an object. Outline a general strategy.

  • Traversing the list;
  • Once the element has been found, remove it.
slide-60
SLIDE 60

public void remove( E o )

void remove( E o ); removes the first (left most) occurrence of an object. Outline a general strategy.

  • Traversing the list;
  • Once the element has been found, remove it.

Difficulty?

slide-61
SLIDE 61

public void remove( E o )

void remove( E o ); removes the first (left most) occurrence of an object. Outline a general strategy.

  • Traversing the list;
  • Once the element has been found, remove it.

Difficulty? You remember that for a singly linked list, we shouldn’t be stopping on the node to be removed since the variable next of the previous node needs to be changed and singly nodes of a singly linked list do not have a previous reference.

slide-62
SLIDE 62

public void remove( E o )

void remove( E o ); removes the first (left most) occurrence of an object. Outline a general strategy.

  • Traversing the list;
  • Once the element has been found, remove it.

Difficulty? You remember that for a singly linked list, we shouldn’t be stopping on the node to be removed since the variable next of the previous node needs to be changed and singly nodes of a singly linked list do not have a previous reference. How about removing the first node?

slide-63
SLIDE 63

public void remove( E o )

void remove( E o ); removes the first (left most) occurrence of an object. Outline a general strategy.

  • Traversing the list;
  • Once the element has been found, remove it.

Difficulty? You remember that for a singly linked list, we shouldn’t be stopping on the node to be removed since the variable next of the previous node needs to be changed and singly nodes of a singly linked list do not have a previous reference. How about removing the first node? Yes, this is a special case, the variable first has to be changed.

slide-64
SLIDE 64

public void remove( E o )

First, consider the public non-recursive method.

slide-65
SLIDE 65

public void remove( E o )

First, consider the public non-recursive method. What are the pre-conditions?

slide-66
SLIDE 66

public void remove( E o )

First, consider the public non-recursive method. What are the pre-conditions? The list should not be empty.

slide-67
SLIDE 67

public void remove( E o )

First, consider the public non-recursive method. What are the pre-conditions? The list should not be empty. When changing the structure of the list, the public non-recursive method often has a special case.

slide-68
SLIDE 68

public void remove( E o )

First, consider the public non-recursive method. What are the pre-conditions? The list should not be empty. When changing the structure of the list, the public non-recursive method often has a special case. What is it?

slide-69
SLIDE 69

public void remove( E o )

First, consider the public non-recursive method. What are the pre-conditions? The list should not be empty. When changing the structure of the list, the public non-recursive method often has a special case. What is it? public void remove( E o ) { if ( first == null ) { throw new NoSuchElementException(); } if ( first.value.equals( o ) ) { first = first.next; } else { remove( first, o ); } } Exercise: “scrubbing the memory”.

slide-70
SLIDE 70

private void remove( Node<E> p, E o )

Remark: for the first call to remove( Node<E> p, E o ), we know that p.value.equals( o ) is false.

slide-71
SLIDE 71

private void remove( Node<E> p, E o )

Remark: for the first call to remove( Node<E> p, E o ), we know that p.value.equals( o ) is false. Indeed, p == first and the case first.value.equals(

  • ) has been processed by the public non-recursive method remove.
slide-72
SLIDE 72

private void remove( Node<E> p, E o )

Remark: for the first call to remove( Node<E> p, E o ), we know that p.value.equals( o ) is false. Indeed, p == first and the case first.value.equals(

  • ) has been processed by the public non-recursive method remove.

We’ll keep that property here too, the method remove( Node<E> p, E o ) will look for an occurrence of o at the position p.next, if the object is found then remove it, otherwise keep going. The recursive method remove knows that the current element has been checked.

slide-73
SLIDE 73

private void remove( Node<E> p, E o )

What is the base case?

slide-74
SLIDE 74

private void remove( Node<E> p, E o )

What is the base case? Singleton (p.next == null).

slide-75
SLIDE 75

private void remove( Node<E> p, E o )

What is the base case? Singleton (p.next == null). What should be done?

slide-76
SLIDE 76

private void remove( Node<E> p, E o )

What is the base case? Singleton (p.next == null). What should be done? Nothing. General case: 1) make a recursive call then post-processing or 2) pre-processing then recursive call (only if necessary).

slide-77
SLIDE 77

private void remove( Node<E> p, E o )

What is the base case? Singleton (p.next == null). What should be done? Nothing. General case: 1) make a recursive call then post-processing or 2) pre-processing then recursive call (only if necessary). Since the method should be removing the leftmost occurrence, the second strategy should be applied.

slide-78
SLIDE 78

private void remove( Node<E> p, E o )

What is the base case? Singleton (p.next == null). What should be done? Nothing. General case: 1) make a recursive call then post-processing or 2) pre-processing then recursive call (only if necessary). Since the method should be removing the leftmost occurrence, the second strategy should be applied. Outline the pre-processing that should be done.

slide-79
SLIDE 79

private void remove( Node<E> p, E o )

What is the base case? Singleton (p.next == null). What should be done? Nothing. General case: 1) make a recursive call then post-processing or 2) pre-processing then recursive call (only if necessary). Since the method should be removing the leftmost occurrence, the second strategy should be applied. Outline the pre-processing that should be done. If o is found at the next position remove it otherwise move forward (make a recursive call).

slide-80
SLIDE 80

private void remove( Node<E> p, E o )

private void remove( Node<E> p, E o ) { if ( p.next == null ) { throw new NoSuchElementException(); } // General case if ( p.next.value.equals( o ) ) { p.next = p.next.next; } else { remove( p.next, o ); } }

slide-81
SLIDE 81

public void remove( E o )

public void remove( E o ) { if ( first == null ) { throw new NoSuchElementException(); } if ( first.value.equals( o ) ) { first = first.next; } else { remove( first, o ); } } private void remove( Node<E> p, E o ) { if ( p.next == null ) { throw new NoSuchElementException(); } if ( p.next.value.equals( o ) ) { p.next = p.next.next; } else { remove( p.next, o ); } }

slide-82
SLIDE 82

Exercises

void add( E c ); adds the element while preserving the natural order of the elements. void removeLast(); removes the last element of a list. void removeLast( E o ); removes the last occurrence of o (this is actually trickier than it seems). void removeAll( E o ); removes all the occurrences of o. void remove( int pos ); remove the element found at position pos.

slide-83
SLIDE 83

LinkedList<E> subList( int fromIndex, int toIndex )

We now consider methods that are returning a list of values.

slide-84
SLIDE 84

LinkedList<E> subList( int fromIndex, int toIndex )

We now consider methods that are returning a list of values. In particular, the method LinkedList<E> subList( int fromIndex, int toIndex ) returns a new LinkedList<E> that contains the elements found in between positions fromIndex and toIndex of the original LinkedList<E> (the elements are not removed from the original list).

slide-85
SLIDE 85

LinkedList<E> subList( int fromIndex, int toIndex )

We now consider methods that are returning a list of values. In particular, the method LinkedList<E> subList( int fromIndex, int toIndex ) returns a new LinkedList<E> that contains the elements found in between positions fromIndex and toIndex of the original LinkedList<E> (the elements are not removed from the original list). One of the main issues is to determine a strategy for building the list of results.

slide-86
SLIDE 86

LinkedList<E> subList( int fromIndex, int toIndex )

We now consider methods that are returning a list of values. In particular, the method LinkedList<E> subList( int fromIndex, int toIndex ) returns a new LinkedList<E> that contains the elements found in between positions fromIndex and toIndex of the original LinkedList<E> (the elements are not removed from the original list). One of the main issues is to determine a strategy for building the list of results. Suggestions?

slide-87
SLIDE 87

LinkedList<E> subList( int fromIndex, int toIndex )

We now consider methods that are returning a list of values. In particular, the method LinkedList<E> subList( int fromIndex, int toIndex ) returns a new LinkedList<E> that contains the elements found in between positions fromIndex and toIndex of the original LinkedList<E> (the elements are not removed from the original list). One of the main issues is to determine a strategy for building the list of results. Suggestions? I will be proposing two strategies, for each them we have to know what is the current position, we’ll the approach developed for the method E get( int index ).

slide-88
SLIDE 88

LinkedList<E> subList( int fromIndex, int toIndex )

We now consider methods that are returning a list of values. In particular, the method LinkedList<E> subList( int fromIndex, int toIndex ) returns a new LinkedList<E> that contains the elements found in between positions fromIndex and toIndex of the original LinkedList<E> (the elements are not removed from the original list). One of the main issues is to determine a strategy for building the list of results. Suggestions? I will be proposing two strategies, for each them we have to know what is the current position, we’ll the approach developed for the method E get( int index ). Strategy 1: traverse the list until the end, when the end is reached return an empty list, following the recursive call, add the current value to the list of result, but only if its position belongs to the interval;

slide-89
SLIDE 89

LinkedList<E> subList( int fromIndex, int toIndex )

We now consider methods that are returning a list of values. In particular, the method LinkedList<E> subList( int fromIndex, int toIndex ) returns a new LinkedList<E> that contains the elements found in between positions fromIndex and toIndex of the original LinkedList<E> (the elements are not removed from the original list). One of the main issues is to determine a strategy for building the list of results. Suggestions? I will be proposing two strategies, for each them we have to know what is the current position, we’ll the approach developed for the method E get( int index ). Strategy 1: traverse the list until the end, when the end is reached return an empty list, following the recursive call, add the current value to the list of result, but only if its position belongs to the interval; Strategy 2: create an empty list to store the values, as the method traverses the list, the elements are added at the end of the list.

slide-90
SLIDE 90

Strategy 1

Recursive calls are traversing the list from head to tail (from left to right), the recursion can be stopped upon reaching the toIndex. Base case: LinkedList<E> result; if ( index == toIndex ) { result = new LinkedList<E>(); result.addFirst( p.value ); }

slide-91
SLIDE 91

Strategy 1

General case: result = subList( p.next, fromIndex, toIndex, index + 1 );

slide-92
SLIDE 92

Strategy 1

General case: result = subList( p.next, fromIndex, toIndex, index + 1 ); What is result?

slide-93
SLIDE 93

Strategy 1

General case: result = subList( p.next, fromIndex, toIndex, index + 1 ); What is result? What’s the next step?

slide-94
SLIDE 94

Strategy 1

General case: result = subList( p.next, fromIndex, toIndex, index + 1 ); What is result? What’s the next step? if ( index > fromIndex ) { result.addFirst( p.value ); }

slide-95
SLIDE 95

Strategy 1

private LinkedList<E> subList( Node<E> p, int fromIndex, int toIndex, int index ) { LinkedList<E> result; if ( index == toIndex ) { result = new LinkedList<E>(); result.addFirst( p.value ); } else { result = subList( p.next, fromIndex, toIndex, index + 1 ); if ( index >= fromIndex ) { result.addFirst( p.value ); } } return result;

Even this more complex method fits the “head+tail” pattern nicely!

slide-96
SLIDE 96

Strategy 1

public LinkedList<E> subList( int fromIndex, int toIndex ) { return subList( first, fromIndex, toIndex, 0 ); } Handling the pre-conditions (illegal range of values) is left as an exercise.

slide-97
SLIDE 97

Strategy 2

In strategy 2, the list used to store the results is created first and filled with elements as the recursive method proceeds. public LinkedList<E> subList( int fromIndex, int toIndex ) { LinkedList<E> result = new LinkedList<E>(); subList( first, result, fromIndex, toIndex, 0 ); return result; }

slide-98
SLIDE 98

Strategy 2

Base case: if ( index == toIndex ) { result.addLast( p.value ); }

slide-99
SLIDE 99

Strategy 2

Base case: if ( index == toIndex ) { result.addLast( p.value ); } result.addLast( p.value ) ou result.addFirst( p.value )?

slide-100
SLIDE 100

Strategy 2

General case: if ( index >= fromIndex ) { result.addLast( p.value ); } subList( p.next, result, fromIndex, toIndex, index + 1 );

slide-101
SLIDE 101

Strategy 2

private void subList( Node<E> p, LinkedList r, int f, int t, int i ) { if ( i == t ) { r.addLast( p.value ); } else { if ( i >= f ) { r.addLast( p.value ); } subList( p.next, r, f, t, i + 1 ); }

Even this more complex method fits the “head+tail” pattern nicely! Where f = fromIndex, t = toIndex, i = index, r = result.

slide-102
SLIDE 102

LinkedList<E> filterLessThan( E c )

LinkedList<E> filterLessThan( E c ) returns in a LinkedList<E> all the elements that are less than c.

slide-103
SLIDE 103

LinkedList<E> filterLessThan( E c )

LinkedList<E> filterLessThan( E c ) returns in a LinkedList<E> all the elements that are less than c. Let’s outline our strategy.

slide-104
SLIDE 104

LinkedList<E> filterLessThan( E c )

LinkedList<E> filterLessThan( E c ) returns in a LinkedList<E> all the elements that are less than c. Let’s outline our strategy. (Base case:) When to stop?

slide-105
SLIDE 105

LinkedList<E> filterLessThan( E c )

LinkedList<E> filterLessThan( E c ) returns in a LinkedList<E> all the elements that are less than c. Let’s outline our strategy. (Base case:) When to stop? At the end of the list, all the elements need to be visited.

slide-106
SLIDE 106

LinkedList<E> filterLessThan( E c )

LinkedList<E> filterLessThan( E c ) returns in a LinkedList<E> all the elements that are less than c. Let’s outline our strategy. (Base case:) When to stop? At the end of the list, all the elements need to be visited. (General case:) What is result? result = filterLessThan( c, p.next );

slide-107
SLIDE 107

LinkedList<E> filterLessThan( E c )

LinkedList<E> filterLessThan( E c ) returns in a LinkedList<E> all the elements that are less than c. Let’s outline our strategy. (Base case:) When to stop? At the end of the list, all the elements need to be visited. (General case:) What is result? result = filterLessThan( c, p.next ); All the elements that are less than c in the list that starts at p.next.

slide-108
SLIDE 108

LinkedList<E> filterLessThan( E c )

LinkedList<E> filterLessThan( E c ) returns in a LinkedList<E> all the elements that are less than c. Let’s outline our strategy. (Base case:) When to stop? At the end of the list, all the elements need to be visited. (General case:) What is result? result = filterLessThan( c, p.next ); All the elements that are less than c in the list that starts at p.next. What is the next step?

slide-109
SLIDE 109

LinkedList<E> filterLessThan( E c )

LinkedList<E> filterLessThan( E c ) returns in a LinkedList<E> all the elements that are less than c. Let’s outline our strategy. (Base case:) When to stop? At the end of the list, all the elements need to be visited. (General case:) What is result? result = filterLessThan( c, p.next ); All the elements that are less than c in the list that starts at p.next. What is the next step? Adding the current element (value) to the list if the value is less than c.

slide-110
SLIDE 110

LinkedList<E> filterLessThan( Node<E> p, LinkedList<E> result, E c )

private void filterLessThan( Node<E> p, LinkedList<E> result, E c ) { if ( p == null ) { return; } filterLessThan( p.next, result, c ); if ( p.value.compareTo( c ) < 0 ) result.addFirst( p.value ); }

slide-111
SLIDE 111

LinkedList<E> filterLessThan( E c )

public LinkedList<E> filterLessThan( E c ) { LinkedList<E> result = new LinkedList<E>(); filterLessThan( first, result, c ); return result; } private void filterLessThan( Node<E> p, LinkedList<E> result, E c ) { if ( p == null ) { return; } filterLessThan( p.next, result, c ); if ( p.value.compareTo( c ) < 0 ) { result.addFirst( p.value ); } }

slide-112
SLIDE 112

LinkedList<E> filterLessThan( E c ) (take 2)

public LinkedList<E> filterLessThan( E c ) { return filterLessThan( first, c ); } private LinkedList<E> filterLessThan( Node<E> p, E c ) { LinkedList<E> result; if ( p == null ) { result = new LinkedList<E>(); } else { result = filterLessThan( p.next, c ); if ( p.value.compareTo( c ) < 0 ) { result.addFirst( p.value ); } } return result; }

slide-113
SLIDE 113

LinkedList<E> filter( Predicate<E> f )

private LinkedList<E> filterLessThan( Node<E> p, E c ) { LinkedList<E> result; if ( p == null ) { result = new LinkedList<E>(); } else { result = filterLessThan( p.next, c ); if ( p.value.compareTo( c ) < 0 ) { result.addFirst( p.value ); } } return result; } What needs to be changed to implement filterGreaterThan?

slide-114
SLIDE 114

LinkedList<E> filter( Predicate<E> f )

private LinkedList<E> filterLessThan( Node<E> p, E c ) { LinkedList<E> result; if ( p == null ) { result = new LinkedList<E>(); } else { result = filterLessThan( p.next, c ); if ( p.value.compareTo( c ) < 0 ) { result.addFirst( p.value ); } } return result; } What needs to be changed to implement filterGreaterThan? How about filterGenderMale?

slide-115
SLIDE 115

LinkedList<E> filter( Predicate<E> f )

private LinkedList<E> filterLessThan( Node<E> p, E c ) { LinkedList<E> result; if ( p == null ) { result = new LinkedList<E>(); } else { result = filterLessThan( p.next, c ); if ( p.value.compareTo( c ) < 0 ) { result.addFirst( p.value ); } } return result; } What needs to be changed to implement filterGreaterThan? How about filterGenderMale? How about . . . ?

slide-116
SLIDE 116

Predicate

public interface Predicate<E> { public abstract boolean evaluate( E arg ); }

slide-117
SLIDE 117

IsNegative

public class IsNegative implements Predicate<Integer> { public boolean evaluate( Integer arg ) { return arg.intValue() < 0; } }

slide-118
SLIDE 118

LinkedList<E> filter( Predicate<E> f )

public LinkedList<E> filter( Predicate<E> f ) { return filter( first, f ); } private LinkedList<E> filter( Node<E> p, Predicate f ) { LinkedList<E> result; if ( p == null ) { result = new LinkedList<E>(); } else { result = filter( p.next, f ); if ( f.evaluate( p.value ) ) { result.addFirst( p.value ); } } return result; }

slide-119
SLIDE 119

IsNegative

l2 = l1.filter( new IsNegative() );

slide-120
SLIDE 120

IsPositive (anonymous)

l2 = l1.filter( new Predicate<Integer>() { public boolean evaluate( Integer arg ) { return args.intValue() > 0; } });

slide-121
SLIDE 121

“Head + tail”

if ( ... ) { // base case calculate results } else { // general case // pre-processing s = method( p.next ); // recursion // post-processing }

slide-122
SLIDE 122

... ...