""" 
A module with just the functions for quick sort.

You can run this by typing "python quick_sort.py" on the command line.

Author: Walker M. White (wmw2), Anne Bracy (awb93)
Date:   May 3, 2018
"""

# HELPER FUNCTIONS
def swap(b, h, k):
    """
    Procedure swaps b[h] and b[k]
    
    Parameter b: The list to rearrange
    Precondition: b is a mutable sequence (e.g. a list).
    
    Parameter h: The first position to swap
    Precondition: h is an int and a valid position in b
    
    Parameter k: The second position to swap
    Precondition: k is an int and a valid position in b
    """
    # We typically do not enforce preconditions on hidden helpers
    temp = b[h]
    b[h] = b[k]
    b[k] = temp

def partition(b, h, k):
    """
    Returns: The new position of pivot in partitioned list b[h..k].
    
    The pivot is the initial value x = b[h].  This function rearranges the
    list so that elements <= x are before the pivot and elements >= x are
    after the pivot.

    Parameter b: The list to rearrange
    Precondition: b is a mutable sequence (e.g. a list).
    
    Parameter h: The starting point to sort
    Precondition: h is an int and a valid position in b
    
    Parameter k: The ending poing to sort
    Precondition: k is an int and a valid position in b
    """
    assert type(b) == list, repr(b)+' is not a list'
    assert 0 <= h and h < len(b), repr(h)+' is not a valid position in the list'
    assert 0 <= k and k < len(b), repr(k)+' is not a valid position in the list'
    
    # position i is end of first paritition range
    i = h
    # position j is beginning of second partition range
    j = k+1
    # Find the first element in the list.
    x = b[h]
        
    # invariant: b[h..i-1] < x, b[i] = x, b[i+1..j-1] unknown, and  b[j..k] >= x
    while i < j-1:
        if b[i+1] >= x:
            # Move this to the end of the block.
            swap(b,i+1,j-1)
            j = j - 1
        else:   # b[i+1] < x
            swap(b,i,i+1)
            i = i + 1
        
    # post: b[h..i-1] < x, b[i] is x, and b[i+1..k] >= x
    return i

def qsort(b, h, k):
    """
    Quick Sort: Sorts the array b[h..k] in n log n average time
    
    Parameter b: The sequence to sort
    Precondition: b is a mutable sequence (e.g. a list).
    
    Parameter h: The starting point to sort
    Precondition: h is an int and a valid position in b
    
    Parameter k: The ending poing to sort
    Precondition: k is an int and a valid position in b
    """

    if k <= h:            # BASE CASE
        return 
    
    # RECURSIVE CASE
    i = partition(b, h, k)
    # b[h..i-1] <= b[i] <= b[i+1..k]
    # Sort b[h..i-1]  and  b[i+1..k]
    qsort(b, h, i-1)
    qsort(b, i+1, k)

my_list = [2,4,6,2,6,9,8,2,3]
print("list before:")
print(my_list)
qsort(my_list, 0, len(my_list)-1)
print("list after quick-sorting:")
print(my_list)