# Algorithms

Document Sample

```					            CScD-501, Design and Analysis of Algorithms
Assignment 2, Spring 2004
Instructor’s Solution
Algorithm 1: Linear search with intelligent up-date.

   Initialize Max1 and Max2 from x[0] and x[1] — one comparison
   Traverse the array starting at subscript k = 2
o If x[k] > Max1, we update BOTH Max1 AND Max2 — one comparison
Max2  Max1
Max1  x[k]
o If x[k] > Max2, just update Max2 — one more comparison
Max2  x[k]

Best case situation: each time we find a new max — note that only one comparison is performed
in that case. Based on the loop structure, it contributes n–2 comparisons, and the initial setting
gives one more: n–1 comparisons in all achieved with forward-sorted data.

Worst case situation: we never discover a new max (x[0] or x[1] contains the maximal value).
Thus we always perform two comparisons. Based on the loop structure, this gives 2(n–2)
comparisons, and the initial setting gives one more: 2n–3 comparisons in all achieved with
reverse-sorted data.

Average case situation: this will be based on how often we find a new max — fairly rare event
with random data. Experimental results show this to deviate very little from the worst case.

Algorithm 2: Recursive search, suggested by text’s optimal MaxMin algorithm

   If size of array segment < 4
o Initialize Max1 and Max2 from the first two cells — one comparison
o If segment size is 3
∆ If unused cell is < Max2, take no further action — one comparison
∆ Otherwise if unused cell is < Max1, update just Max2 — one more comparison
∆ Otherwise update both Max1 and Max2
   Otherwise recursively get the two largest elements in the left and the right half
o If left Max1 > right Max1 — one comparison
Max1  left Max1
Max2  larger of left Max2 or right Max1 — one comparison
o Otherwise
Max1  right Max1
Max2  larger of right Max2 or left Max1 — one comparison

Printed 2012-Jul-30 at 08:42
Analysis

Basis cases:
Size 2: single comparison
Size 3: one comparison based on the first two cells
one comparison to check for update based on the unused cell
IF that is used, perform one more comparison to determine the extent of the update

Recursive case:
Comparison based on the two recursive calls plus always two comparisons to select the two
maximal elements

nc(n) = nc(n/2)left + nc(n/2)right + 2

Thus we can build tables deriving from the two base cases. In addition, the size-3 base case
supports a best case (third cell is NOT used, for two comparisons — reverse-sorted data) and a
worst case (third cell IS used, for three comparisons — forward-sorted data).

n   nc(n)         n   nc_b(n)   nc_w(n)
2       1         3         2         3
4       4         6         6         8
8     10         12       14        18
16     22         24       30        38
32     46         48       62        78
64     94         96      126       158

Starting from n=2, we find a linear relationship:
nc(n) = 3/2 n – 2

Starting from n=3, we find two linear relationships, one for best case, the other for worst case:
nc_b(n) = 4/3 n – 2
nc_w(n) = 5/3 n – 2

The proof of these equations from the recurrence and the base cases given is straight-forward.

For sizes that are not cleanly either a power of two or three times a power of two, we have a
mixing of the base cases. Odd base-case behavior grows in as we progress from 2k up to 1.5 2k
(the point at which all base cases involve three), and then diminishes up to 2k+1 — the
experimental results show this clearly.

The average case, from experimental runs, seems roughly to average together the two behaviors
when there is an odd-sized base case, for approximately nc(n) = 3/2 n – 2. There seems,
however, to be more contribution from the “worst-case” side, so that the average plot bows
upwards between powers of two. You can see this by sighting along the curve from the edge of
the page.

Printed 2012-Jul-30 at 08:42
Algorithm 1: Linear Search

140

120
Number of comparisons

100

80

60

40

20

0
0   8   16        24         32        40            48   56   64
Array Size

F(alg-1)     A(Alg-1)      R(Alg-1)

Printed 2012-Jul-30 at 08:42
Algorithm 2: Recursive Search, based at 2 and 3

140

120
Number of Comparisons

100

80

60

40

20

0
0   8        16        24         32        40          48   56   64
Array Size

F(alg-2)     A(Alg-2)    R(Alg-2)

Printed 2012-Jul-30 at 08:42
Optimal Algorithm: Single Elimination Tournament With List Traversal

As discussed in Ch. 10 of our text, the optimal solution to this problem uses a single-elimination
tournament in which winners retain a linked list of opponents that have lost to them. When there
is only one player left, the second-ranked player will necessarily have lost to this player
sometime. This particular tournament does not have players in seeded positions, so it is possible
that “Max2” lost to “Max1” at the very beginning of the tournament.

For a single-elimination tournament, we need to have a power of two for the initial positions.
This generates the possibility of a “bye” — player[k] is playing against player[k+1], but if there
is no player[k+1], then player[k] advances to the next round of the tournament automatically,
even if there is no player[k]. For instance, if we have 2k+1 players, and we use the pairing
indicated above (i.e., adjacent players contend with each other), the half of the tournament that
consists of player 2k+1 through player 2k+1 will pass player 2k+1 through with a series of “byes”
until that player is matched with the winner of the matching player 1 through player 2k in the
final match.

Analysis is easiest for the situation where the array size is an even power to 2: n = 2k. The
tournament player will involve 2k-1 + 2k-2 + . . . + 2 + 1 comparisons: n–1. The list of losers will
reflect the number of matches — the binary tree size, which is given by log(n), that is, k.

When the array size is not an even power of 2, the tournament comparisons reflect all the
matches with two players — the “byes” do not require comparisons. The final traversal of the
loser list will vary depending on how many “byes” were encountered. Thus the best case will
that in which the data are sorted in a forward direction (so that the largest element is in the last
position), since the last element will encounter the largest number of “byes”. The very best case
will be that with 2k+1 array elements with the largest at the end. That element will be passed
forward by “byes” until the final match, so that its loser list will have only a single entry — the
second-largest element in the array.

The code, unfortunately, becomes more . . . convoluted to perform the tournament, maintain the
loser lists, and then find the runner-up. Also, the code example attached is in Java. Were this
implemented in an environment without automatic garbage collection, the algorithm would need
to be reworked to eliminate the massive memory leaks that a naïve translation would generate.

Side note: what if . . . we decided to find the second-largest by doing a double-elimination
tournament. That is, the first time an entry loses, it enters into a second tournament that is
played by those who have lost once. The second-largest should then succeed in winning this
tournament, so we don’t have to have all those . . . lists!

The problem is that the consolation tournament has initial size 2k-1, meaning that it will take
2k-1 – 1 comparisons, so that the two tournaments together put us back at about 3/2 n.

Printed 2012-Jul-30 at 08:42
Tournament Implementation

80
70
Number of Comparisons

60
50
40
Note: Fwd sorted data generates
30                                             numerous "byes" in the
20                                                 tournament

10
0
0   8   16       24        32        40            48    56        64
Array Size

T(Fwd)     T(AvgRnd)        T(Rev)

Printed 2012-Jul-30 at 08:42
Finding the Largest Two Entries in an Array
Sequential Algorithm — Intelligent Update of Second Largest                    else                                 // RECURSIVE CASE
{//NOTE: Each recursive instance needs local scratch objects
MyInt v1a = new MyInt(),
static void maxPair( MyInt[] x, MyInt maxValue1, MyInt maxValue2 )                      v1b = new MyInt(),
{                                                                                       v2a = new MyInt(),
int k, n = x.length;                                                                 v2b = new MyInt();
int   mid = (hi + lo) / 2;
if ( x[0].compareTo(x[1]) > 0 )                                               top2( x, lo, mid, v1a, v2a );
{ maxValue1.set(x[0]); maxValue2.set(x[1]);    }                              top2( x, mid+1, hi, v1b, v2b );
else                                                                       // True max in left pair
{ maxValue1.set(x[1]); maxValue2.set(x[0]);    }                              if ( v1a.compareTo(v1b) > 0 )
for ( k = 2; k < n; k++ )                                                     {
{                                                                                v1.set(v1a);
if ( x[k].compareTo(maxValue1) > 0 )                                       // Possible 2nd max: 1st right or 2nd left
{                                                                             if ( v1b.compareTo(v2a) > 0 )
maxValue2.set(maxValue1);                                                     v2.set(v1b);
maxValue1.set(x[k]);                                                       else
}                                                                                v2.set(v2a);
else if ( x[k].compareTo(maxValue2) > 0 )                                  }
maxValue2.set(x[k]);                                                 // True max in right pair
}                                                                             else
}                                                                                 {
v1.set(v1b);
// Possible 2nd max: 1st left or 2nd right
Recursive Algorithm — Consolidate two pairs of maximal items                         if ( v1a.compareTo(v2b) > 0 )
v2.set(v1a);
/**                                                                                  else
* Recursive method to find the top 2 values                                            v2.set(v2b);
*                                                                                }
* Base cases: sizes 2 and 3 --- presumably never called with hi==lo           }
*                                                                         }
* For size 2, simply set in order. Then for size 3, adjust based on the
* extra value.
*
* For size > 3, find the top two values of the left and the right side.
* Then select the top two based on those two ORDERED pairs.
*/
static void top2 ( MyInt[] x, int lo, int hi, MyInt v1, MyInt v2 )
{ if ( (hi-lo) < 3 )                      // BASE CASE
{//Either size two or size three
if ( x[lo].compareTo(x[lo+1]) < 0 )
{ v1.set(x[lo+1]); v2.set(x[lo]); }
else
{ v1.set(x[lo]); v2.set(x[lo+1]); }
if ( (hi-lo) == 2 ) // That is, size of 3
if ( x[hi].compareTo(v2) > 0 )
if ( x[hi].compareTo(v1) > 0 )
{ v2.set(v1); v1.set(x[hi]); }
else
v2.set(x[hi]);
// else NOTHING
// If third value LESS than second, there is NO correction.
}

Printed 2012-Jul-30 at 08:42
Optimal Algorithm: Single-Elimination Tournament With Addendum                        size >>= 1;    // Right shift by one <==> divide by two
}
mx1.set(player[0].get());
/**
current = player[0].next;
* Single-elimination tournament to find largest AND SECOND-LARGEST.
t1 = current.get();
*
current = current.next;
* For each win, maintain a stack-discipline list of the losing players.
while ( current != null )
* When there is only one winner left, its loser list will necessarily
{
* contain the second-largest. Traverse that list to find the second
t2 = current.get();
* largest.
if ( t2.compareTo(t1) > 0 )
*
t1 = t2;
* The tournament necessarily involves a power-of-two number of players.
current = current.next;
* The initial one (or more) rounds will involve some "byes" --- if there
}
* is no player[k+1], then player[k] advances to the next round.
mx2.set(t1);
*/
}
static void tournament ( MyInt[] x, MyInt mx1, MyInt mx2 )
{//Header cell contains this object from x[], and the start of the
// linked list of objects that have LOST to this object.                    Mutable Integer Class MyInt
MyIntList[] player;
MyIntList   current;   // Used in the traversal to find mx2
class MyInt implements Comparable
MyInt       t1,        // Object pulled from a player
{ static int nCmp = 0;
t2;        // Ditto
int value;
int size = 1,          // Physical size of player[]
j, k,              // subscripts and loop variables                      MyInt()
n = x.length;                                                            { set(0);   }
// Find the power of two >= n                                                   MyInt (int value)
while ( size < n )                                                           { set(value); }
size += size;
void set (int value)
player = new MyIntList[size]; // Initialized with null references            { this.value = value;   }
for ( j = 0; j < n; j++ )                                                    void set (MyInt item)
player[j] = new MyIntList(x[j], null);                                    { this.value = item.value;   }
while ( size > 1 )                                                           int get ()
{ for ( j = k = 0; k < size; j++, k += 2 )                                   { return value;     }
{ if ( player[k+1] == null )
{ player[j] = player[k];                                               public int compareTo(Object r)
if ( DEBUG )                                                        { MyInt right = (MyInt) r;
System.out.println ("Bye for position " + k);                       nCmp++;
}                                                                         return this.value - right.value;
else                                                                   }
{ t1 = player[k].get();
// Comparison NOT included in the count
t2 = player[k+1].get();
public int check(MyInt right)
if ( t1.compareTo(t2) > 0 )
{ return this.value - right.value; }
{ player[k].next = new MyIntList ( t2, player[k].next );
player[j] = player[k];                                           public String toString()
if (DEBUG)                                                       { return Integer.toString(value);     }
System.out.println ("Winner in position " + k );
}                                                                   static public int nCompares()
else                                                                { int rtn = nCmp;
{ player[k+1].next = new MyIntList ( t1, player[k+1].next );           nCmp = 0;
player[j] = player[k+1];                                            return rtn;
if (DEBUG)                                                       }
System.out.println ("Winner in position " + (k+1) );      }
}
}
}
Printed 2012-Jul-30 at 08:42

```
DOCUMENT INFO
Categories:
Tags:
Stats:
 views: 2 posted: 7/30/2012 language: pages: 8