'''
This is a type of divide and conquer algorithm which divides the search space into
3 parts and finds the target value based on the property of the array or list 
(usually monotonic property).

Time Complexity  : O(log3 N)
Space Complexity : O(1)
'''

import sys

# This is the precision for this function which can be altered.
# It is recommended for users to keep this number greater than or equal to 10.
precision = 10

# This is the linear search that will occur after the search space has become smaller.
def lin_search(left, right, A, target):
    for i in range(left, right+1):
        if(A[i] == target):
            return i

# This is the iterative method of the ternary search algorithm.
def ite_ternary_search(A, target):
    left = 0
    right = len(A) - 1;
    while(True):
        if(left<right):
            
            if(right-left < precision):
                return lin_search(left,right,A,target)

            oneThird = (left+right)/3+1;
            twoThird = 2*(left+right)/3+1;
            
            if(A[oneThird] == target):
                return oneThird
            elif(A[twoThird] == target):
                return twoThird
            
            elif(target < A[oneThird]):
                right = oneThird-1
            elif(A[twoThird] < target):
                left = twoThird+1
            
            else:
                left = oneThird+1
                right = twoThird-1
        else:
            return None

# This is the recursive method of the ternary search algorithm.
def rec_ternary_search(left, right, A, target):
    if(left<right):
        
        if(right-left < precision):
            return lin_search(left,right,A,target)

        oneThird = (left+right)/3+1;
        twoThird = 2*(left+right)/3+1;

        if(A[oneThird] == target):
            return oneThird
        elif(A[twoThird] == target):
            return twoThird
        
        elif(target < A[oneThird]):
            return rec_ternary_search(left, oneThird-1, A, target)
        elif(A[twoThird] < target):
            return rec_ternary_search(twoThird+1, right, A, target)
        
        else:
            return rec_ternary_search(oneThird+1, twoThird-1, A, target)
    else:
        return None

# This function is to check if the array is sorted.
def __assert_sorted(collection):
    if collection != sorted(collection):
        raise ValueError('Collection must be sorted')
    return True


if __name__ == '__main__':
    
    # For python 2.x and 3.x compatibility: 3.x has not raw_input builtin
    # otherwise 2.x's input builtin function is too "smart"
    
    if sys.version_info.major < 3:
        input_function = raw_input
    else:
        input_function = input

    user_input = input_function('Enter numbers separated by coma:\n')
    collection = [int(item) for item in user_input.split(',')]

    try:
        __assert_sorted(collection)
    except ValueError:
        sys.exit('Sequence must be sorted to apply the ternary search')

    target_input = input_function(
        'Enter a single number to be found in the list:\n'
    )
    target = int(target_input)
    result1 = ite_ternary_search(collection, target)
    result2 = rec_ternary_search(0, len(collection)-1, collection, target)
    
    if result2 is not None:
        print('Iterative search: {} found at positions: {}'.format(target, result1))
        print('Recursive search: {} found at positions: {}'.format(target, result2))
    else:
        print('Not found')