Python Algorithms

A Tale of two tournaments

Although there are many types of tournaments, let's consider two rather common ones, with rather catchy names.

These are the round-robin tournament and the knockout tournament.

In a round-robin tournament(or, specifically, a single round-robin tournament), each contestant meets each of the others in turn. The question then becomes, how many matches or fixtures do we need, if we have, for example, n knights jousting? In a knockout tournament, the competitors are arranged in pairs, and only the winner from each pair goes on to the next round. Here there are more questions to ask: for n knights, how many rounds do we need, and how many matches will there be, in total?

Shaking Hands

The round-robin problem is exactly equivalent to another well-known puzzler: if you have n algorists meeting at a conference and they all shake hands, how many handsshakes do you get? Or, equivalently, how many edges are there in a complete graph with n nodes? It's the same count you get in all kinds of "all against all" situations. For example, if you have n locations on a map and want to find the two that are closest to each other, the simple (brute-force) approach would be compare all points with all others.

The Hare and the tortoise

Let's say our knights are 100 in number and that the tournament staff are still a bit tired from last year's round robin.(Quite understandable, as there would have been 4950 matches.) They decide to introduce the (more efficient) knockout system and want to know how many matches they'll need. 

Now comes the blindingly obvious part: in each match, one knight is knocked out. All except the winner are knocked out, so we need n-1 matches to leave only one standing.(The tournament structure is illustrated as a rooted tree in Figure, where each leaf is a knight and each internal node represents a match).

The upper limit, h-1, is the number of rounds.( so 2h =n).

Here's the first lesson about doubling, then: a perfectly balanced binary tree(that is , a rooted tree where all internal nodes have two children and all leaves have the same depth) has n-1 internal nodes.

The hare and the tortoise are meant to represent the width and height of the tree, respectively.

h = lgn

n = 2h

Let's do a game I like to call "think of a particle.". I think of one of the particles in the visible universe, and you try to guess which one, using only yes/no question.

By asking only yes/no questions, you can pinpoint any particle in the observable universe in about five minutes! This is a class example of why logarithmic algorithms are so super-sweet.

This is an example of bisection, or binary search, one of the most important and well-known logarithmic algorithms.

By now, I hope you're starting to see how exponentials and logarithms are the inverses of one another.

At level 1, there are two node, each of which has n/2 tokens; at level 2, we have four nodes, with n/4 tokens, and so forth. The sum across any row is always n.

The string length k, will be the height of the tree, and the number of possible strings will equal the number of leaves, 2k.

Another, more direct way to see this is to consider the number of possibilities at each step: the first bit can be zero or one, and for each of these values, the second also has two possibilites, and so forth. It's like k nested for loops, each running two iterations, the total count is still 2k.

Recursion

def S(seq,i=0):
    if i==len(seq): return 0
    return S(seq,i+1)+seq[i]

sample call

seq=range(100)
S(seq)

Some basic Recurrences with Solutions, as well as some sample applications

# Recurrence Solution Example Applications
1 T(n) = T(n-1) + 1 Θ(n) Processing a sequence, for example, with reduce
2 T(n) = T(n-1) + n Θ(n2) Handshake problems
3 T(n) = 2T(n-1) + 1 Θ(2n) Towers of Hanoi
4 T(n) = 2T(n-1) + n Θ(2n)  
5 T(n) = T(n/2) + 1 Θ(lgn) Binary search
6 T(n) = T(n/2) + n Θ(n) Randomized Select, average case.
7 T(n) = 2T(n/2) + 1 Θ(n) Tree Traversal
8 T(n) = 2T(n/2) + n Θ(nlgn) Sorting by divide and conquer
       

two algorithms to show python' simplicity

def gsort(seq):
    i =0
    while i< len(seq):
        if i==0 or seq[i-1]<=seq[i]:
            i +=1
        else:
            seq[i],seq[i-1] = seq[i-1],seq[i]
            i -=1

mergesort

def mergesort(seq): 
  mid = len(seq)//2 
  lft, rgt = seq[:mid], seq[mid:] 
  if len(lft) > 1: lft = mergesort(lft) 
  if len(rgt) > 1: rgt = mergesort(rgt) 
  res = [] 
  while lft and rgt: 
    if lft[-1] >= rgt[-1]: 
      res.append(lft.pop()) 
    else: 
      res.append(rgt.pop()) 
  res.reverse() 
  return (lft or rgt) + res

 

 

posted on 2012-08-16 09:26  grep  阅读(769)  评论(0编辑  收藏  举报