基于Python的十大基础排序算法解析和实现

本章总结希尔排序归并排序快速排序

编程环境

Win10、Python3.7.0、Jupyter Notebook

思想与实现

1、希尔排序

希尔排序也叫做递减增量排序法,是插入排序的优化版本。先将整个待排序的记录序列分割成为若干子序列,然后分别进行直接插入排序,待整个序列中的记录"基本有序"时,再对全体记录进行依次直接插入排序。

算法步骤:

1、选择一个增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1;
2、按增量序列个数 k,对序列进行 k 趟排序;
3、每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

步骤图解:

文字还是比较难理解的,那我用图来表示:

1.首先设置一个初始的未排序的序列,如下图

python 数列递减 python递减排序_快速排序


2.设置初始增量gap,gap=length/2=5,即列表长度/2,意味着会分成5组。分组的规则是将当前数字的后面与第gap个数(即第5个)组成一组,得到的结果如下图:

python 数列递减 python递减排序_排序算法_02


3.然后对这5个组进行直接插入排序,排序的时候只在组内排序,组间不排序。如组[56,93]会排序成[93,56],最后结果如下:

python 数列递减 python递减排序_排序算法_03


4.排序之后继续将增量递减,即 gap=gap/2=2(取整)。算法会得到如下分组:

python 数列递减 python递减排序_python_04


5.排序依旧是组内排序,组间不排序。排序后结果如下:

python 数列递减 python递减排序_排序算法_05


6.我们可以看到,列表的数值已经是比较清晰的了,最后gap=gap/2=1,即最后对整个列表排序,结果如下:

python 数列递减 python递减排序_合并排序_06

代码实现
# 希尔排序
def shell_sort(l): 
    n = len(l)
    gap = n//2
  
    while gap > 0: 
        for i in range(gap,n): 
            temp = l[i] 
            j = i 
            while  j >= gap and arr[j-gap] >temp: 
                l[j] = l[j-gap] 
                j -= gap 
            l[j] = temp 
        gap = n//2
    return l
        
        
arr = [93,2,23,46,13,56,412,55,21,3]
print(shell_sort(arr))

输出结果:[2, 3, 13, 21, 23, 46, 55, 56, 93, 412]

2、归并排序

归并排序是一个典型的采用了分治法(即分而治之思想),且建立在归并操作上的排序算法。简单来说就把大问题分成小问题(原始数据切分成一段段的数据)后,对小问题的答案汇总到一起。

算法步骤

1、申请空间(其大小为两个已经排序序列之和),该空间用来存放合并后的序列;
2、设定两个指针,最初位置分别为两个已经排序序列的起始位置;
3、比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
4、重复步骤 3 直到某一指针达到序列尾;
5、将另一序列剩下的所有元素直接复制到合并序列尾。

算法图解

python 数列递减 python递减排序_合并排序_07

代码实现
# 归并排序
def merge_sort(arr):
    import math
    if(len(arr)<2):
        return arr
    middle = math.floor(len(arr)/2)
    left, right = arr[0:middle], arr[middle:]
    return merge(merge_sort(left), merge_sort(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

arr = [93,2,23,46,13,56,412,55,21,3]
print(merge_sort(arr))

输出结果:[2, 3, 13, 21, 23, 46, 55, 56, 93, 412]

2、快速排序

快速排序的本质也是使用分治法实现的。它的思想比较容易理解,实现是使用递归实现的(需要有一点递归的基础),简单来说就是在序列中随便取一个数A,比A大的放在A的右边,比A小的放在A的左边,放完之后A的左右两边都形成一个小序列,对这些小序列重复进行类似的操作即可。

算法步骤

1、从数列中挑出一个元素,称为 “基准”(pivot);
1、重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置;
2、重复第2步,即递归地把小于基准值元素的子数列和大于基准值元素的子数列排序。

代码实现
# 快速排序

def quickly_sort(l, start, end):
    if start >= end:
        return
    
    q = l[start]
    left, right = start, end
    
    while left < right:
        while left < right and l[right] >= q:
            right -= 1
        l[left] = l[right]
        
        while left < right and l[left] < q:
            left += 1
        l[right] = l[left]
        
    l[left] = q
    quickly_sort(l, start, left-1)
    quickly_sort(l, left+1, end)

arr = [93,2,23,46,13,56,412,55,21,3]
quickly_sort(arr, 0, len(arr) - 1)
print(arr)

输出结果:[2, 3, 13, 21, 23, 46, 55, 56, 93, 412]

未完待续,接下来的文章会总结堆排序、计数排序、桶排序和基数排序