Saturday, April 21, 2012

Sorting Algorithms in Python

Below are some popular sorting algorithms implemented in Python.
#!/usr/bin/env python

class BubbleSort(object):
    @staticmethod
    def sort(l):
        new_list = list(l)
        while True:
            swapped = False
            for i in xrange(0, len(new_list)-1):
                if new_list[i] > new_list[i+1]:
                    new_list[i], new_list[i+1] = new_list[i+1], new_list[i]
                    swapped = True
            if not swapped: break
        return new_list

class SelectionSort(object):
    @staticmethod
    def sort(l):
        new_list = list(l)
        for i in xrange(0, len(new_list)):
            min_index = i
            for j in xrange(i, len(new_list)):
                if new_list[j] < new_list[min_index]:
                    min_index = j
            new_list[i], new_list[min_index] = new_list[min_index], new_list[i]
        return new_list

class InsertionSort(object):
    @staticmethod
    def sort(l):
        new_list = list(l)
        for i in xrange(1, len(new_list)):
            j = i
            while j > 0 and new_list[j] < new_list[j-1]:
                new_list[j-1], new_list[j] = new_list[j], new_list[j-1]
                j -= 1
        return new_list

class ShellSort(object):
    @staticmethod
    def sort(l):
        new_list = list(l)
        n = len(l)
        h = 1
        while h < (n/3): h = (3*h) + 1
        while h >= 1:
            for i in xrange(h, n):
                j = i
                while j >=h and new_list[j] < new_list[j-h]:
                    new_list[j], new_list[j-h] = new_list[j-h], new_list[j]
                    j -= h
            h /= 3
        return new_list

class MergeSort(object):
    @staticmethod
    def sort(l):
        new_list = list(l)
        MergeSort.msort(new_list, 0, len(new_list)-1)
        return new_list
    
    @staticmethod
    def msort(l, lo, hi):
        if lo == hi: return
        mi = (lo + hi) / 2
        MergeSort.msort(l, lo, mi)
        MergeSort.msort(l, mi + 1, hi)
        MergeSort.merge(l, lo, mi, hi)
    
    @staticmethod
    def merge(a, lo, mi, hi):
        i = lo
        j = mi + 1
        tmp = list(a)
        hi = hi + 1
        for x in xrange(lo, hi):
            if i > mi:
                a[x] = tmp[j]
                j += 1
            elif j >= hi:
                a[x] = tmp[i]
                i += 1
            elif tmp[i] < tmp[j]:
                a[x] = tmp[i]
                i += 1
            else:
                a[x] = tmp[j]
                j += 1

class QuickSort(object):
    @staticmethod
    def sort(l):
        new_list = list(l)
        import random
        random.shuffle(new_list)
        QuickSort.qsort(new_list, 0, len(new_list)-1)
        return new_list
    
    @staticmethod
    def qsort(l, lo, hi):
        if hi <= lo: return
        j = QuickSort.partition(l, lo, hi)
        QuickSort.qsort(l, lo, j-1)
        QuickSort.qsort(l, j+1, hi)
    
    @staticmethod
    def partition(l, lo, hi):
        i = lo
        j = hi + 1
        v = l[lo]
        while True:
            i += 1
            while l[i] < v:
                if i == hi: break
                i += 1
            j -= 1
            while v < l[j]:
                if j == lo: break
                j -= 1
            if i >= j: break
            l[i], l[j] = l[j], l[i]
        l[lo], l[j] = l[j], l[lo]
        return j

class HeapSort(object):
    @staticmethod
    def sort(l):
        new_list = list(l)
        n = len(new_list)
        # construct a binary heap
        for i in xrange(n/2, 0, -1):
            HeapSort.sink(new_list, i, n)
        # sort down the heap
        for i in xrange(n, 0, -1):
            new_list[i-1], new_list[0] = new_list[0], new_list[i-1]
            HeapSort.sink(new_list, 1, i-1)
        return new_list
    
    @staticmethod
    def sink(l, current_pos, n):
        child_pos = HeapSort.get_child_position(l, current_pos, n)
        if child_pos == -1: return
            
        while l[child_pos-1] > l[current_pos-1]:
            l[child_pos-1], l[current_pos-1] = l[current_pos-1], l[child_pos-1]
            current_pos = child_pos
            child_pos = HeapSort.get_child_position(l, current_pos, n)
            if child_pos == -1: break
            
    @staticmethod
    def get_child_position(l, current_pos, n):
        first_child_pos = 2 * current_pos
        second_child_pos = (2 * current_pos) + 1
        child_pos = -1 # no child
        # no child
        if first_child_pos > n: return child_pos
        # there's only one child
        if second_child_pos > n: child_pos = first_child_pos
        else: # there are two children
            if l[first_child_pos-1] > l[second_child_pos-1]:
                child_pos = first_child_pos
            else:
                child_pos = second_child_pos
        return child_pos
    
if __name__ == "__main__":
   expected_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
   input_list = [9, 3, 6, 5, 7, 1, 8, 10, 2, 4]

   sorted_list = BubbleSort.sort(input_list)
   assert sorted_list == expected_list

   sorted_list = SelectionSort.sort(input_list)
   assert sorted_list == expected_list

   sorted_list = InsertionSort.sort(input_list)
   assert sorted_list == expected_list

   sorted_list = ShellSort.sort(input_list)
   assert sorted_list == expected_list
   
   sorted_list = MergeSort.sort(input_list)
   assert sorted_list == expected_list

   sorted_list = QuickSort.sort(input_list)
   assert sorted_list == expected_list
   
   sorted_list = HeapSort.sort(input_list)
   assert sorted_list == expected_list

No comments:

Post a Comment