Mistriter
3/23/2020 - 7:52 AM

ALG001 排序

十大经典排序算法实现

#! /usr/bin/env python
# -*- coding: UTF-8 -*-

"""
@Author: LuMingdong

@License: (C) Copyright 2017.

@Contact: lumingdong@live.cn

@Project: Alg

@File: Sort.py.py

@Create Date: 2019/11/28 0028 14:37

@Version: 1.0

@Description: Now is better than never.  ——The Zen of Python

"""


# 1. bubbleSort
def bubbleSort(arr):
    for i in range(1, len(arr)):  # 对L-1个位置进行迭代
        for j in range(0, len(arr)-i):  #  最后的是最大的,对比次数每次都减小1次
            if arr[j] > arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]
    return arr
# 优化:https://blog.csdn.net/hansionz/article/details/80822494

# 2. selectionSort
def selectionSort(arr):
    for i in range(0, len(arr)-1):
        minIndex = i
        for j in range(i+1, len(arr)):
            if arr[j] < arr[minIndex]:
                minIndex = j
        if i != minIndex:
            arr[i], arr[minIndex] = arr[minIndex], arr[i]
    return arr


# 3. insertionSort
def insertionSort(arr):
    for i in range(len(arr)):
        preIndex = i - 1
        current = arr[i]
        while preIndex >= 0 and arr[preIndex] > current:
            arr[preIndex+1] = arr[preIndex]
            preIndex -= 1
        arr[preIndex+1] = current
    return arr


# 4. 优化:(拆半插入)希尔排序
# 动画: https://www.jianshu.com/p/40dcc3b83ddc
# 希尔排序利用分组粗调的方式减少了直接插入的工作量
# 分组的方式可以是按排序元素总数逐步折半进行跨越选取,如8个元素所使用的分组跨度为(4,2,1),被称为希尔排序的增量,
# 增量的选择可以有很多种,这里所用的逐步折半的增量方法,是Donald Shell在发明希尔排序时提出的一种朴素方法,被称为希尔增量。
"""
希尔排序是插入排序的一种改进版本,Donald Shell在1959年提出而得名。

希尔排序的实现思路:设定一个缩小增量的规则,以某个增量对数组进行分组,对每个分组进行直接插入排序,然后缩小增量再次分组依次类推,直到增量缩小到1,程序结束。

希尔排序的时间复杂度与增量序列的选取有关。关键词比较次数、记录移动次数和增量序列选择之间的关系,至今没有一个统一的公式可以归纳。
在中小规模的排序中,希尔排序占优,在大规模数据量的排序中快排占优。在实际场景中根据测试数据结果选择使用哪种排序。

稳定性:不稳定,相同的元素可能会颠倒位置。

希尔排序的核心在于间隔序列的设定。既可以提前设定好间隔序列,也可以动态的定义间隔序列。
动态定义间隔序列的算法是《算法(第4版》的合著者Robert Sedgewick提出的。在这里,我就使用了这种方法。
"""
def shellSort(arr):
    gap = 1
    while gap < len(arr)/3:
        gap = gap * 3 + 1   # 动态定义间隔序列
        print gap
    while gap > 0:
        for i in range(gap, len(arr)):
            temp = arr[i]
            j = i - gap
            while j >= 0 and arr[j] > temp:
                arr[j+gap] = arr[j]
                j -= gap
            arr[j+gap] = temp
        gap = gap / 3  # gap // 3 (in python3)
        print gap
    return arr


# 5. 归并排序
def mergeSort(arr):
    if len(arr) < 2:
        return arr
    middle = len(arr) / 2  # len(arr)//2 (in Python3)
    left, right = arr[:middle], arr[middle:]
    return merge(mergeSort(left), mergeSort(right))

def merge(left, right):
    result = []
    while left and right:
        if left[0] <= right[0]:
            result.append(left.pop(0))
        else:
            result.append(right.pop(0))
    while left:
        result.append(left.pop(0))
    while right:
        result.append(right.pop(0))
    return result


# 6.快速排序,QuickSort
def quickSort(arr, left=None, right=None):
    left = left if isinstance(left, (int, float)) else 0
    right = right if isinstance(right, (int, float)) else len(arr)-1
    if left < right:
        partitionIndex = partition(arr, left, right)
        quickSort(arr, left, partitionIndex-1)
        quickSort(arr, partitionIndex+1, right)
    return arr

def partition(arr, left, right):
    povit = left
    j = povit + 1  # j是处理区分界点
    i = j  # i是循环指针
    while i <= right:
        print 'i=', i
        if arr[i] < arr[povit]:
            swap(arr, i, j)
            print 'j=', j
            j += 1
        i += 1
    swap(arr, povit, j-1)
    return j-1

def swap(arr, i, j):
    arr[i], arr[j] = arr[j], arr[i]

# 7.堆排序(HeapSort)

# 8.桶排序(BucketSort)
def bucketSort(arr, bucket_size=5):
    if len(arr) == 0:
        return arr
    min_value, max_value = arr[0], arr[0]
    for i in range(len(arr)):
        if arr[i] < min_value:
            min_value = arr[i]
        elif arr[i] > max_value:
            max_value = arr[i]

    bucket_count = (max_value - min_value) / bucket_size + 1
    buckets = [[] for x in range(bucket_count)]

    for i in range(len(arr)):
        buckets[(arr[i]-min_value)/bucket_size].append(arr[i])  # map to bucket

    sorted_arr = []
    for i in range(bucket_count):
        quickSort(buckets[i])
        for v in range(len(buckets[i])):
            sorted_arr.append(buckets[i][v])
    return sorted_arr

# 8.计数排序
def countingSort(arr, max_value=None):
    if max_value is None:
        max_value = max(arr)
    bucket_len = max_value + 1
    buckets = [0] * bucket_len
    sorted_index = 0
    for i in range(len(arr)):
        if not buckets[arr[i]]:
            buckets[arr[i]] = 0
        buckets[arr[i]] += 1
    for j in range(bucket_len):
        while buckets[j] > 0:
            arr[sorted_index] = j
            sorted_index += 1
            buckets[j] -= 1
    return arr

# 9.基数排序

def radix(arr):
    digit = 0
    max_digit = 1
    max_value = max(arr)
    # 找出列表中最大的位数
    while 10 ** max_digit < max_value:
        max_digit = max_digit + 1

    while digit < max_digit:
        temp = [[] for i in range(10)]
        for i in arr:
            # 求出每一个元素的个、十、百位的值
            t = int((i / 10 ** digit) % 10)
            temp[t].append(i)

        coll = []
        for bucket in temp:
            for i in bucket:
                coll.append(i)

        arr = coll
        digit = digit + 1

    return arr


# main
if __name__ == '__main__':
    arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
    print radix(arr)