def selectKth(A, k, l, r):
    idx = selectPivotIndex(A, l, r)
    pivotIdx = partition(A, l, r, idx)

    if l + k - 1 == pivotIdx:
        return pivotIdx

    if l + k - 1 < pivotIdx:
        return selectKth(A, k, l, pivotIdx - 1)
    else:
        return selectKth(A, k - (pivotIdx - l + 1), pivotIdx + 1, r)


#! Note there is also a non-recursive way to implment this
def mediansort(A, l, r):
    if r <= l:
        return

    mid = int((r - l + 1) / 2)
    me = selectKth(A, mid + 1, l, r)

    mediansort(A, l, l + mid - 1)
    mediansort(A, l + mid + 1, r)


#-- Run -------------------------------------#

if __name__ == "__main__":

    testalgo(mediansort)
		insertionsort( B[i], 0, len(B[i]) )

		for m in range(0,len(B[i])):

			A[idx] = B[i][m]
			idx += 1

def bucketsort( A ):

	# Purely for demonstation purposes
	hashN = 5 

	B = [ [] for _ in xrange(hashN) ]

	for i in range(0,len(A)):
		k = hash(A[i], hashN )
		B[k].append( A[i] )

	extract( B, A )

#-- Run ----------------------#

if __name__ == "__main__":

	testalgo( bucketsort )






def selectPivotIndex(A, l, r):
    return int((l + r) / 2)


def partition(A, l, r):
    p = selectPivotIndex(A, l, r)
    swap(A, p, r)
    store = l
    for i in range(l, r):
        if cmp(A[i], A[r]) <= 0:
            swap(A, i, store)
            store += 1
    swap(A, store, r)
    return store


def quicksort(A, l, r):
    if l < r:
        pi = partition(A, l, r)
        quicksort(A, l, pi - 1)
        quicksort(A, pi + 1, r)


#-- Run -------------------------------------#

if __name__ == "__main__":

    testalgo(quicksort)
use for small and nearly sorted arrays

works by expanding sorted area one element
at a time.
'''

from common import cmp, randomArray, testalgo

#-- Methods -------------------------------------#


def insert(arr, idx):
    i = idx - 1
    val = arr[idx]
    while i >= 0 and cmp(arr[i], val) > 0:
        arr[i + 1] = arr[i]
        i -= 1
    arr[i + 1] = val


def insertionsort(arr, l, r):
    for j in range(1, len(arr)):
        insert(arr, j)


#-- Run -------------------------------------#

if __name__ == "__main__":

    testalgo(insertionsort)
from common import cmp, swap, log, testalgo

#-- Methods -------------------------------------#

def selectPivotIndex(A,l,r):
	return int( (l+r)/2 )

def partition(A,l,r):
	p = selectPivotIndex(A,l,r)
	swap(A,p,r)
	store = l
	for i in range(l,r):
		if cmp(A[i], A[r]) <= 0:
			swap(A,i,store)
			store += 1
	swap(A,store,r)
	return store
 
def quicksort( A, l, r ):
	if l < r:
		pi = partition(A,l,r)
		quicksort(A,l,pi-1)
		quicksort(A,pi+1,r)

#-- Run -------------------------------------#

if __name__ == "__main__":

	testalgo( quicksort )
	return int( (l+r)/2 )

def selectKth(A, k, l, r):
	idx = selectPivotIndex(A,l,r)
	pivotIdx = partition(A,l,r,idx)

	if l+k-1 == pivotIdx:
		return pivotIdx

	if l+k-1 < pivotIdx :
		return selectKth(A, k, l, pivotIdx-1)
	else:
 		return selectKth(A, k-(pivotIdx-l+1), pivotIdx+1, r)

#! Note there is also a non-recursive way to implment this
def mediansort( A, l, r ):
	if r <= l:
		return

	mid = int( (r-l+1)/2 )
	me = selectKth(A, mid+1, l, r)

	mediansort( A, l, l+mid-1)
	mediansort(A, l+mid+1, r)

#-- Run -------------------------------------#

if __name__ == "__main__":

	testalgo( mediansort )
    l = 2 * idx + 1
    r = 2 * idx + 2
    if l < max and A[l] > A[idx]:
        largest = l
    else:
        largest = idx
    if r < max and A[r] > A[largest]:
        largest = r
    if largest != idx:
        swap(A, idx, largest)
        heapify(A, largest, max)


def buildHeap(A):
    for i in range(int(len(A) / 2) - 1, -1, -1):  # range is [ |n/2|-1 ... 0 ]
        heapify(A, i, len(A))


def heapsort(A, l, r):  # note l and r not used here
    buildHeap(A)
    for i in range(len(A) - 1, 0, -1):  # range is [ n-1 ... 0 ]
        swap(A, 0, i)
        heapify(A, 0, i)


#-- Run -------------------------------------#

if __name__ == "__main__":

    testalgo(heapsort)
'''>
insertion sort
use for small and nearly sorted arrays

works by expanding sorted area one element
at a time.
'''

from common import cmp, randomArray, testalgo

#-- Methods -------------------------------------#

def insert( arr, idx ):
	i = idx - 1
	val = arr[idx]
	while i >=0 and cmp( arr[i], val ) > 0 :
		arr[i+1] = arr[i]
		i -= 1	
	arr[i+1] = val

def insertionsort( arr, l, r ):
	for j in range(1, len(arr)):
		insert( arr, j )

#-- Run -------------------------------------#

if __name__ == "__main__":

	testalgo( insertionsort )
def heapify(A,idx,max):
	l = 2*idx+1
	r = 2*idx+2
	if l < max and A[l] > A[idx] :
		largest = l
	else:
		largest = idx
	if r < max and A[r] > A[largest] :
		largest = r
	if largest != idx :
		swap( A, idx, largest )
		heapify( A, largest, max)

def buildHeap(A):
	for i in range(int(len(A)/2)-1,-1,-1): # range is [ |n/2|-1 ... 0 ]
		heapify(A,i,len(A))

def heapsort(A, l, r): # note l and r not used here
	buildHeap(A)
	for i in range(len(A)-1,0,-1): # range is [ n-1 ... 0 ]
		swap(A,0,i)
		heapify(A,0,i)

#-- Run -------------------------------------#

if __name__ == "__main__":

	testalgo( heapsort )