#-*-Coding:utf-8-*-
From random import Randint
From math import ceil, floor
def _partition (A, L, R, I):
"" "" "in A[i] is the main element dividing the array a[l ... R], so that:
A[l.. M-1] <= a[m] < A[M+1..R]
"""
A[i], a[r] = A[r], a[i] # I exchange to the lowest R, as the principal element
Pivot = a[r] # main Dollar
m = L # index Tag
For N in Xrange (L, R): # L. R-1
If A[n] <= pivot:
A[M], a[n] = A[n], A[m] # Exchange
M + = 1 # move back
A[M], a[r] = A[r], A[m] # Main to M-bit
return m
def _rand (A, L, R):
"" "randomly dividing the main element" "
Return Randint (L, R) # A[l. R] randomly take a
def _select (A, L, R, K, pivot_selector = _rand):
"" Use the fast Platoon, get a[l. R] The number of K small, k in [l+1,r+1]:
Its tail recursion way, pseudo code is as follows:
SELECT (A, L, R, K)
1 while true:
2 i←? Dividing the principal element position
3 M←partition (A, L, R, I)//array Partitioning
4 n←m-l + 1//a[l. M] Number of elements
5 if k = n//check a[m] is a small element of K
6 then return a[m]
7 ElseIf k < n//left partition
8 R = M-1
9 Else//right partition
Ten k = K-n
One L = m + 1
Args:
Pivot_selector (Function): Primary selection method, default random Way
"""
If not A:
Return None
if L = = r:
return A[l]
While True:
i = Pivot_selector (A, L, R)
m = _partition (A, L, R, i)
n = m-l + 1
if k = = N:
return A[m]
Elif K < n:
r = M-1
Else
K = K-n
L = m + 1
def rand_select (A, K):
"" "The default random partitioning of the main element mode, k in [1, Len (A)]
E[t (n)] = O (n)
"""
Return _select (A, 0, Len (a)-1, k);
def _median (A, L, R):
"" to A[l. R] After inserting the sort (in situ), select the number of digits in the position ""
For j in Xrange (L, R + 1):
K = A[j]
i = j
While I > L and a[i-1] > K:
A[i] = a[i-1]
I-= 1
A[i] = k
return L + int ((r-l) * 0.5) # down Median
def _medianofmedians (A, L, R):
The median of the median means:
1. Divided into floor (N/5) a 5-tuple, leaving (n%5) the last group.
2. Find out the median of the Ceil (N/5) group. First, sort each group, and then select the median.
3. Repeat for the ceil (N/5) median found in step 2nd until there is only one median.
"""
if L = = r:
return L
n = r-l + 1 # element number
m = Int (ceil (n/5.0)) # divides the number of groups, 5 elements per group
For I in Xrange (m):
# Start and end bits per group
sub_l = L + i * 5
Sub_r = sub_l + 4
If Sub_r > R:
Sub_r = R
# after each set of elements is inserted, select the median
Sub_m = _median (A, sub_l, sub_r) # Median index
# Exchange Median to previous few
j = L + I
A[J], a[sub_m] = A[sub_m], a[j]
Return _medianofmedians (A, L, L + m-1) # median number of digits
def bfprt_select (A, K):
Median (bfprt algorithm) for "" "median number of digits
T (n) = O (n)
"""
Return _select (A, 0, Len (a)-1, K, _medianofmedians);
def _median3 (A, L, R):
"" "Three median way, take l,r, (l+r)/23 number Median" ""
c = (L + r)/2
Keys = [L, c, R]
i = _median (keys, 0, 2)
return Keys[i]
def median_select (A, K):
"" "in three digits to eliminate the worst-case scenario" "
Return _select (A, 0, Len (a)-1, K, _median3);
if __name__ = = ' __main__ ':
Import random, Time
From copy import copy
Print (' Preparing data ... ')
n = 1000000
Nums = Range (n)
Random.shuffle (Nums)
Print (' Ready go! ')
def timeit (FNC, *args, **kargs):
print ('%s Starts processing '% fnc.__name__)
begtime = Time.clock ()
retval = FNC (*args, **kargs)
Endtime = Time.clock ()
print ('%s takes time:%f '% (fnc.__name__, Endtime -Begtime)
return retval
Test_methods = [Rand_select, Bfprt_select, Median_select]
K = Random.randrange (n) + 1
dashes = '---' * 10
For Test in Test_methods:
Print (dashes)
nums_new = Copy (nums)
result = Timeit (test, nums_new, K)
Print (' The%dth smallest element:%d '% (k, result))