introduction to computer science recursive link operations mergesort unit 18

49
Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

Post on 21-Dec-2015

235 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

Introduction to Computer Science

• Recursive Link Operations

• MergeSort

Unit 18Unit 18

Page 2: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 2

Let's Use This Encapsulated Definition of a Node Object

class ListNode {private int _value;private ListNode _tail;

public ListNode (int v, ListNode next) {_value = v; _tail = next;

}

public int getValue ( ) {return _value; }

public ListNode getTail ( ) {return _tail;}}

Page 3: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 3

Recursive Functions Over Lists

• Linked Lists (and other data structures using links) are well suited for recursive treatment, just as arrays are

• But first, let’s review an iterative treatment of handling lists

• Example: Read in a list of numbers from the user (any length), then print them in reverse order

Page 4: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 4

User Enters:

Enter number: 2

Enter number: 3

Enter number: 5

Enter number: 7

Enter number: 11

Enter number: ^D or ^Z

_tail

_value

>>>>

11_tail

_value7

_tail

_value3

>>>>_tail

_value

null

2

>>>>

We create:

_tail

_value5

>>>>

We print:11 7 5 3 2

theList

Page 5: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 5

Outline of Solution

class PrintReversed {

static ListNode readReverseList ( ) { … }

static void printReverseList(ListNode n) { … }

public static void main (String[ ] args) {

ListNode theList = readReverseList( );

printReverseList(theList);

}

}

Page 6: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 6

Iterative readReverseList( )

static ListNode readReverseList ( ) {int inputval;ListNode front = null;SimpleInput sinp = new SimpleInput(System.in);System.out.print("Enter number: ");inputval = sinp.readInt( );while ( !sinp.eof( ) ) {

front = new ListNode(inputval, front);System.out.print("Enter number: ");inputval = sinp.readInt( );

}System.out.println( );return front;

}

Page 7: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 7

Trace It

inputval = sinp.readInt( );while ( !sinp.eof( ) ) {

front = new ListNode(inputval, front);System.out.print("Enter number: ”);inputval = sinp.readInt( );

}

front is null

null

Page 8: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 8

Trace It (1)

tail

value

null

2

frontheap

inputval = sinp.readInt( );while ( !sinp.eof( ) ) {

front = new ListNode(inputval, front);System.out.print("Enter number: ”);inputval = sinp.readInt( );

}

Two things are happening:the use of front (and inputval) to initialize the new

node, then the resetting of front to point to the node

Page 9: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 9

Trace It (2)

tail

value

nulltail

value

>>>>

3 2

Two things are happening:the use of front (and inputval) to initialize the new

node, then the resetting of front to point to the node

frontheap

inputval = sinp.readInt( );while ( !sinp.eof( ) ) {

front = new ListNode(inputval, front);System.out.print("Enter number: ”);inputval = sinp.readInt( );

}

Page 10: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 10

Iterative printReverseList( )

static void printReverseList(ListNode head) {

while ( head != null ) {System.out.print(head.getValue() + " ");head = head.getTail( );

}System.out.println();

}

Page 11: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 11

Now Recursive – Add some more Methods to the ListNode class

• Let's add a new methodint length ( )to the ListNode class that computes the length of the list (recursively)

class ListNode {private int _value;private ListNode _tail;

public ListNode (int v, ListNode next) {_value = v; _tail = next;

}

public int length ( ) { … }

public int getValue ( ) { return _value; }

public ListNode getTail ( ) { return _tail; }}

Page 12: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 12

It's Easy When You Think Recursively

public int length ( ) {if (_tail == null)

return 1;else

return ( 1 + _tail.length( ) );}

We are sending the length message (recursively) to the tail of the current object (i.e., the object pointed to

by the current object's tail)

Page 13: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 13

class ListNode {private int _value;private ListNode _tail;

public ListNode (int v, ListNode next) {_value = v; _tail = next;

}

public String toString ( ) { … }

public int length ( ) { … }

public int getValue ( ) { return _value; }

public ListNode getTail ( ) { return _tail; }}

Let's Try it Again

• Let's add another new methodString toString ( )to the ListNode class that prints the elements of the list, separated by commas

Page 14: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 14

It's Easy When You Think Recursively

public String toString ( ) {String myValue = Integer.toString(_value);if (_tail == null) return myValue;else return (myValue + ", " +

_tail.toString( ) );}

Integer.toString( ) converts an integer to a String object. Normally we wouldn't need to do the conversion manually,

except when tail == null and it's the last item in the list.

Page 15: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 15

class ListNode {private int _value;private ListNode _tail;

public ListNode (int v, ListNode next) {_value = v; _tail = next;

}

public ListNode nth (int n) { … }

public String toString ( ) { … }

public int length ( ) { … }

public int getValue ( ) { return _value; }

public ListNode getTail ( ) { return _tail; }}

We're Not Done Yet

• Let's add another new method, ListNode nth ( )to the ListNode class that returns a reference to the nth cell in the list

Page 16: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 16

It's Easy When You Think Recursively

public ListNode nth (int n) {if (n == 0)

return this;else if (_tail == null)

return null;else

return _tail.nth(n - 1);}

If n is 0, we return the head of the list, namely the object that got the message, i.e., "this". If n is not 0, but the tail is null, the list is too short, and I return

null. Otherwise, I request the n-1th element from my tail object.

Page 17: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 17

class ListNode {private int _value;private ListNode _tail;

public ListNode (int v, ListNode next) {_value = v; _tail = next;

}

public void addToEndM (int n) { … }

public ListNode nth (int n) { … }

public String toString ( ) { … }

…}

Let's Add a Mutating List Operation (alters the list)

• Let's add another new, mutating, methodvoid addToEndM (int n) to the ListNode class that adds a new cell (initialized with n) to the end of the list

Page 18: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 18

No need to return a value, since it simply alters the end of the list

public void addToEndM (int n) {if (_tail != null)// we're a cell in the middle of the list

_tail.addToEndM(n);else // we're the last cell

_tail = new ListNode(n, null);}

When we're not at the end of the list (that is, _tail != null), we just pass the addToEndM(n) message down

to our tail object. When we are the last cell, we create a new object, initialize it with n and null, then set our

(formerly null) tail to it.

Page 19: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 19

OK, One More Mutating List Operation

• Let's add one more new, mutating, methodListNode addInorderM (int n)to the ListNode class that adds a new cell (initialized with n) into the list in the correct numerical order (assuming the list was ordered to begin with)

• Do not insert duplicates

• If we always use addInorderM to add cells to the list, it will remain ordered

Page 20: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 20

No need to return a value, since it simply alters the end of the list

public ListNode addInorderM (int n) {if (n < _value)

return ( new ListNode(n, this) );else if (n == _value)

return this;else if (_tail == null) {

_tail = new ListNode(n, null);return this;

}else {

_tail = _tail.addInorderM(n);return this;

}}

Page 21: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 21

Case Analyis

• There are four possible situations to consider

• They depend on whether we are in the middle of the list or the end of the list

• They also depend on whether the current cell's value (call it p) compares with the value to be inserted (call it n)

Page 22: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 22

Case 1: p is greater than n

We initialize a new node with the value n, point it at the current node ("this"), and return a pointer to it

if (n < _value)return ( new ListNode(n, this) );

_tail

_value

>>>>_tail

_value

>>>>

n p_tail

_value

>>>>

Page 23: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 23

Case 2: p equals n

We ignore n, since the problem statement said not to insert duplicates

else if (n == _value)return this;

_tail

_value

>>>>

p_tail

_value

>>>>

Page 24: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 24

Case 3: p is less than n, but the current object's tail is null

We initialize a new node with the value n and the tail null, point the current cell's tail to it, and return a pointer to the current cell

_tail

_value

>>>>_tail

_value

null

np

else if (_tail == null) {_tail = new ListNode(n, null);return this;

}

Page 25: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 25

Case 4: p is less than n, and the current object's tail is not null

We pass along the call to the current object's tail, set the current object's tail to whatever is returned, and return a reference to the current object

_tail

_value

>>>>_tail

_value

>>>>

p …_tail

_value

>>>>

else {_tail = _tail.addInorderM(n);return this;

}

Page 26: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 26

MergeSort

• Exploits the same divide-and-conquer strategy as QuickSort

• Better suited for linked lists

• Divide the linked list in 2 nearly equal-sized parts

• Recursively MergeSort the 2 halves

• Merge the two halves back together

Page 27: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 27

MergeSort

_tail

_value

null_tail

_value

>>>>

1 15_tail

_value

>>>>

4_tail

_value

>>>>_tail

_value

>>>>

3 9_tail

_value

>>>>

17 …

1. Split into two equal sized lists

tail

value

>>>>tail

value

>>>>

… …tail

value

>>>>

…tail

value

>>>>tail

value

>>>>

… …tail

value

>>>>

tail

value

>>>>tail

value

>>>>

… …tail

value

>>>>

…tail

value

>>>>tail

value

>>>>

… …tail

value

>>>>

2. Sort recursively 3. Sort recursively

4. Merge the two sorted liststail

value

nulltail

value

>>>>

15 17tail

value

>>>>

9tail

value

>>>>tail

value

>>>>

3 4tail

value

>>>>

1 …

Page 28: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 28

What Makes Up MergeSort?

• We need to be able to carry out two operations

• Splitting a linked list into two pieces

• Merging two ordered linked lists into a single ordered linked list

• Let's look at merging

Page 29: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 29

Merging Two SortedLinked Lists

_tail

_value

null_tail

_value

>>>>

5 8_tail

_value

>>>>

3_tail

_value

>>>>_tail

_value

>>>>

1 1_tail

_value

>>>>

0_tail

_value

>>>>

2

_tail

_value

null_tail

_value

>>>>

4 8_tail

_value

>>>>

2_tail

_value

>>>>

1

Gives us:

tail

value

>>>>tail

value

>>>>

2 3tail

value

>>>>

2tail

value

>>>>tail

value

>>>>

1 1tail

value

>>>>

0tail

value

>>>>

1tail

value

nulltail

value

>>>>

8 8tail

value

>>>>

5tail

value

>>>>

4

Page 30: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 30

merge( ) will be nonmutating

• We'll write merge as a nonmutating method: ListNode merge (ListNode L)

• One list node will bethe receiver:

• The other list node will bethe argument:

• The returned value will (generally) be a new list node, creating a new list (though parts of the old lists may appear in it)

tail

value

nulltail

value

>>>>

5 8tail

value

>>>>

3tail

value

>>>>tail

value

>>>>

1 1tail

value

>>>>

0tail

value

>>>>

2

tail

value

nulltail

value

>>>>

4 8tail

value

>>>>

2tail

value

>>>>

1

tail

value

>>>>tail

value

>>>>

2 3tail

value

>>>>

2tail

value

>>>>tail

value

>>>>

1 1tail

value

>>>>

0tail

value

>>>>

1tail

value

nulltail

value

>>>>

8 8tail

value

>>>>

5tail

value

>>>>

4

Page 31: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 31

merge( )

ListNode merge (ListNode L) { if (L == null)

return this; if (_value < L._value)

if (_tail == null)return new ListNode(_value, L);

elsereturn new ListNode(_value,

_tail.merge(L)); else

return new ListNode(L._value,

merge(L._tail));}

Page 32: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 32

Case Analysis of merge( )

• There are four possible situations to consider–The argument L is null

–My value is less than the head of L's value, but my tail is null

–My value is less than the head of L's value, and my tail is not null

–My value is greater than or equal to the head of L's value

Page 33: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 33

The argument L is null

Just return myself, i.e., the rest of the first list:

return this;

_tail

_value

null

8_tail

_value

>>>>_tail

_value

>>>>

1 1_tail

_value

>>>>

0

receiver: L:null

_tail

_value

null

8_tail

_value

>>>>_tail

_value

>>>>

1 1_tail

_value

>>>>

0

return:

Page 34: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 34

My value is less than the head of L's value, but my tail is null

Build a new ListNode, with my value in it and tail pointing to L

return new ListNode(_value, L);

_tail

_value0

receiver: L:null

_tail

_value

null_tail

_value

>>>>

4 8_tail

_value

>>>>

2_tail

_value

>>>>

1

_tail

_value

>>>>

0

return:

_tail

_value

null_tail

_value

>>>>

4 8_tail

_value

>>>>

2_tail

_value

>>>>

1

L

Page 35: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 35

My value is less than the head of L's value, and my tail is not null

Build a new ListNode, with my value in it and tail pointing to result of merge( ), sent to my tail, with L as the argument

return new ListNode(_value, _tail.merge(L));

L:

_tail

_value

>>>>

4_tail

_value

>>>>

2_tail

_value

>>>>

1

_tail

_value

>>>>

0

return: L, the argument

_tail

_value

>>>>

1_tail

_value

>>>>

0

receiver:

… …

_tail

_value

>>>>

4_tail

_value

>>>>

2_tail

_value

>>>>

1

…_tail

_value

>>>>

1

merge( ) recursive call to merge

Page 36: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 36

My value is greater than or equal to the head of L's value

Build a new ListNode, with L head's value in it and tail pointing to result of merge( ) sent to myself, with L's tail as argument

return new ListNode(L._value, merge(L._tail));

L:

_tail

_value

>>>>

4_tail

_value

>>>>

2_tail

_value

>>>>

1

_tail

_value

>>>>

1

return: L's tail, the argument

_tail

_value

>>>>

4_tail

_value

>>>>

3

receiver:

… …

_tail

_value

>>>>

4_tail

_value

>>>>

2_tail

_value

>>>>

4

…_tail

_value

>>>>

3

merge( ) recursive call to merge

Page 37: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 37

Splitting a list

• We want to take a linked list, and split it in two, without having to go all the way through, counting nodes, then going half-way through to split

• One list will be 1st, 3rd, 5th, … members

• The second list will be 2nd, 4th, 6th, … members

• Maintain their original relative order

Page 38: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 38

Splitting a list

_tail

_value

null_tail

_value

>>>>

22 36_tail

_value

>>>>

21_tail

_value

>>>>_tail

_value

>>>>

1 3_tail

_value

>>>>

0_tail

_value

>>>>

7

Becomes:

_tail

_value

>>>>_tail

_value

>>>>

3 21_tail

_value

>>>>

0_tail

_value

null

36

_tail

_value

null_tail

_value

>>>>

7 22_tail

_value

>>>>

1

Page 39: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 39

First Key Idea

• We will call the split( ) method on a list (node), and return two lists

• For this purpose, we'll define a new type of object, ListNodePair, that holds (pointers) to two ListNodes

A ListNodePair object variable

Page 40: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 40

Second Key Idea

• When splitting, the roles of even-indexed and odd-indexed positions become interchanged

• The first list consists of the 1, 3, 5, 7 nodes, and the second of the 2, 4, 6 nodes, but when the first node is removed, the rest of the first list consists of even nodes, and the second of the odd nodes…

Page 41: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 41

Odd becomes Even…

_tail

_value

null_tail

_value

>>>>

22 36_tail

_value

>>>>

21_tail

_value

>>>>_tail

_value

>>>>

1 3_tail

_value

>>>>

0_tail

_value

>>>>

7

First list,odds

_tail

_value

null_tail

_value

>>>>

22 36_tail

_value

>>>>

21_tail

_value

>>>>_tail

_value

>>>>

1 3_tail

_value

>>>>

0_tail

_value

>>>>

7

First list,first item removed, now holds evens

Page 42: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 42

class ListNodePair

class ListNodePair {private ListNode _a, _b;

public ListNodePair (ListNode a,ListNode b) {

this._a = a;

this._b = b;}

public ListNode x( ) { return _a; }

public ListNode y( ) { return _b; }}

Page 43: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 43

split( )

ListNodePair split ( ) {if (_tail == null)

return new ListNodePair(this, null);else {

ListNodePair p = _tail.split( );

return new ListNodePair(

new ListNode(_value, p.y( )),

p.x( ) );

}}

Page 44: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 44

Analysis of split( );tail of list is null

Return a new ListNodePair, with the first list being the original list, the second list being null

return new ListNodePair(this, null);

_tail

_value

null

8Original list:

return:null

_tail

_value

null

8

Page 45: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 45

If tail of list is not null,do two things

• Split the tail of the list, putting one part in the first cell of a ListNodePair p, the second part in the second cell of that ListNodePair

• Add a new ListNode, with my value, at the front of the second part, switching the two parts' location (because of the even/odd flipping that occurs at each recursive level)

ListNodePair p = _tail.split( );return new ListNodePair(

new ListNode(_value, p.y( )), p.x( ) );

Page 46: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 46

Split the tail of the list

_tail

_value

null_tail

_value

>>>>

22 36_tail

_value

>>>>

21_tail

_value

>>>>_tail

_value

>>>>

1 3_tail

_value

>>>>

0_tail

_value

>>>>

7

Original list:

Result of recursive call, p = tail.split( );

p

_tail

_value

>>>>_tail

_value

>>>>

1 7_tail

_value

null

22_tail

_value

>>>>_tail

_value

>>>>

3 21_tail

_value

null

36

ListNodePair p = _tail.split( );

p.x( ) p.y( )

Page 47: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 47

Add a new ListNode, with my value, at the front of the second part; switch first and second parts

return new ListNodePair(new ListNode(_value, p.y( )), p.x( ) );

_tail

_value

>>>>_tail

_value

>>>>

1 7_tail

_value

null

22_tail

_value

>>>>_tail

_value

>>>>

3 21_tail

_value

null

36_tail

_value

>>>>

0

return:

New ListNode

New ListNodePair

p.y( ) p.x( )

Page 48: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 48

mergeSort( ),exploit divide-and-conquer

static ListNode mergeSort ( ListNode L ) {// Sort L by recursively splitting and merging

if ( (L == null) || (L.getTail( ) == null) )return L; // Zero or one item

else { // Two or more items//Split it in two partsListNodePair p = L.split( );// …then sort and merge the two partsreturnmergeSort(p.x( )).merge(mergeSort(p.y( )));

}} mergeSort first list…and merge…with mergeSort of second

list

Page 49: Introduction to Computer Science Recursive Link Operations MergeSort Unit 18

18- 49

Complexity of mergeSort( )

• MergeSort is O(nlog2n)

• It always has this performance

• QuickSort, in contrast, has this performance on average, but can also have quadratic ( O(n2) ) performance, worst case

• However, there is overhead in using linked lists instead of arrays