Sorting Algorithm
Setup and Driver Program
Each sorting algorithm is implemented as a Python function, which will sort the list in-place. I used the following piece of code to test all the algorithms.
import random
random_items = [random.randint(-50, 100) for c in range(32)]
print 'Before: ', random_items
insertion_sort(random_items)
print 'After : ', random_items
Bubble Sort
It’s basic idea is to bubble up the largest(or smallest), then the 2nd largest and the the 3rd and so on to the end of the list. Each bubble up takes a full sweep through the list.
The difference between bubble sort and insertion sort is only at the direction and start/end point of comparison. So during study, pay special attention
The inner level loop:
- Bubble sort:
start from begin of list (each time is one element shorter in the end) - Insertion sort:
start from end of list (the inner list grows with outer loop)
def bubble_sort(items):
""" Implementation of bubble sort """
for i in range(len(items)):
for j in range(len(items)-1-i):
if items[j] > items[j+1]:
items[j], items[j+1] = items[j+1], items[j] # Swap!
Insertion Sort
Sorting is typically done in-place, by iterating up the array, growing the sorted list behind it. At each array-position, it checks the value there against the largest value in the sorted list (which happens to be next to it, in the previous array-position checked). If larger, it leaves the element in place and moves to the next. If smaller, it finds the correct position within the sorted list, shifts all the larger values up to make a space, and inserts into that correct position.
The most common variant of insertion sort, which operates on arrays, can be described as follows:
- Suppose there exists a function called Insert designed to insert a value into a sorted sequence at the beginning of an array. It operates by beginning at the end of the sequence and shifting each element one place to the right until a suitable position is found for the new element. The function has the side effect of overwriting the value stored immediately after the sorted sequence in the array.
- To perform an insertion sort, begin at the left-most element of the array and invoke Insert to insert each element encountered into its correct position. The ordered sequence into which the element is inserted is stored at the beginning of the array in the set of indices already examined. Each insertion overwrites a single value: the value being inserted.
def insertion_sort(items):
""" Implementation of insertion sort """
for i in range(1, len(items)):
j = i
# use while loop, because if any comp is correct, we don't need to compare the rest (think this while loop as insertion function)
while j > 0 and items[j] < items[j-1]:
items[j], items[j-1] = items[j-1], items[j]
j -= 1
Merge Sort
# in-place merge sort
def merge_sort(items):
""" Implementation of mergesort """
if len(items) > 1:
mid = len(items) / 2 # Determine the midpoint and split
left = items[0:mid]
right = items[mid:]
merge_sort(left) # Sort left list in-place
merge_sort(right) # Sort right list in-place
l, r = 0, 0
for i in range(len(items)): # Merging the left and right list
# s1: get lval and rval, from left and right subarray
# set to None if subarray is run out
lval = left[l] if l < len(left) else None
rval = right[r] if r < len(right) else None
# learn this way of experssion
# also pay attention that we should use l < len(left)
# s2: compare and modify original array in-place
if (lval and rval and lval < rval) or rval is None:
items[i] = lval # update in-place
l += 1
elif (lval and rval and lval >= rval) or lval is None:
items[i] = rval
r += 1
else:
raise Exception('Could not merge, sub arrays sizes do not match the main array')
Quick Sort
# in-place quick sort
def quick_sort(items):
""" Implementation of quick sort """
if len(items) > 1:
pivot_index = len(items) / 2
smaller_items = []
larger_items = []
for i, val in enumerate(items):
if i != pivot_index:
if val < items[pivot_index]:
smaller_items.append(val)
else:
larger_items.append(val)
quick_sort(smaller_items)
quick_sort(larger_items)
items[:] = smaller_items + [items[pivot_index]] + larger_items
# this syntax is crucial !!
Heap Sort
import heapq
def heap_sort(items):
""" Implementation of heap sort """
heapq.heapify(items)
items[:] = [heapq.heappop(items) for i in range(len(items))]
Parsing & Evaluating Reverse Polish Notation in Python
The Reverse Polish Noation (RPN) is a mathematical notation to define a sequence of steps where the operator follows the operand. This post will show you how to parse and evaluate them in Python. This exercise will then allow us to go one step further and write an Infix Notation evaluator to parse standard simple mathematic formulas.
"""
The expresion is read from left to right. We split the string by spaces and
get a list of items to evaluate. If the item is a number, we push
it down the stack. If the item is an operand, we pop
two numbers from the stack, perform the operation and push
the result back on the stack. At the end, what’s left on the stack is the answer!
"""
def parse_rpn(expression):
""" Evaluate a reverse polish notation """
stack = []
for val in expression.split(' '):
if val in ['-', '+', '*', '/']:
op1 = stack.pop()
op2 = stack.pop()
if val=='-': result = op2 - op1
if val=='+': result = op2 + op1
if val=='*': result = op2 * op1
if val=='/': result = op2 / op1
stack.append(result)
else:
stack.append(float(val))
return stack.pop()
# The main program to try parse_rpn()
if __name__ == '__main__':
expression = '10 3 5 + *'
result = parse_rpn(expression)
print result
expression = '3 5 + 10 *'
result = parse_rpn(expression)
print result