稳定的排序和非稳定的排序

参考文章链接:http://wuchong.me/blog/2014/02/09/algorithm-sort-summary/

稳定的

冒泡排序(bubble sort) — O(n2)
插入排序 (insertion sort)— O(n2)
归并排序 (merge sort)— O(n log n)
  

不稳定

选择排序 (selection sort)— O(n2)
希尔排序 (shell sort)— O(n log n)
堆排序 (heapsort)— O(n log n)
快速排序 (quicksort)— O(n log n)

冒泡排序(相邻交换)

基本原理

1.比较相邻的元素。如果第一个比第二个大,就交换他们两个。
2.对第0个到第n-1个数据做同样的工作。这时,最大的数就“浮”到了数组最后的位置上。
3.针对所有的元素重复以上的步骤,除了最后一个。
4.持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
某一趟遍历如果没有数据交换,则说明已经排好序了,因此不用再进行迭代了。用一个标记记录这个状态即可。

#冒泡排序
def bubble_sort(arry):
    n = len(arry)
    for i in range(n-1,0,-1):
        flag = 1
        for j in range(0,i):
            if arry[j] > arry[j+1]:
                arry[j],arry[j+1] = arry[j+1],arry[j]
                flag = 0
        if flag:
             break
    return arry
if __name__ == '__main__':
    disorder_arry  = [10,9,8,7,6,5,4,3,2,1]
    order_arry = bubble_sort(disorder_arry)
    print(order_arry)
#某一趟遍历如果没有数据交换,则说明已经排好序了,因此不用再进行迭代了。用一个标记记录这个状态即可。

选择排序(选择最小交换)

#选择排序
def select_sort(arry):
    n = len(arry)
    for i in range(0,n):
        min = i
        for j in range(i+1,n):
            if arry[j] < arry[min]:
                min = j
        arry[min],arry[i] = arry[i],arry[min]
    return arry

if __name__ == '__main__':
    disorder_arry  = [3,2,1]
    order_arry = select_sort(disorder_arry)
    print(order_arry)

插入排序(将元素插入到有序数组中)

基本原理

1.从第一个元素开始,该元素可以认为已经被排序
2.取出下一个元素,在已经排序的元素序列中从后向前扫描
3.如果被扫描的元素(已排序)大于新元素,将该元素后移一位
4.重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
5.将新元素插入到该位置后
6.重复步骤2~5

#插入排序
def insert_sort(arry):
    n = len(arry)
    for i in range(1,n):
        if arry[i] < arry[i-1]:
            temp = arry[i]
            index = i
            for j in range(i-1,-1,-1):
                if arry[j] > temp:
                    arry[j+1] = arry[j]
                    index = j
                else:
                    break
            arry[index] = temp
    return arry

if __name__ == '__main__':
    disorder_arry  = [3,2,1,4]
    order_arry = insert_sort(disorder_arry)
    print(order_arry)

希尔排序

基本原理

希尔排序,也称递减增量排序算法,实质是分组插入排序。由 Donald Shell 于1959年提出。希尔排序是非稳定排序算法。

希尔排序的基本思想是:将数组列在一个表中并对列分别进行插入排序,重复这过程,不过每次用更长的列(步长更长了,列数更少了)来进行。最后整个表就只有一列了。将数组转换至表是为了更好地理解这算法,算法本身还是使用数组进行排序。

例如,假设有这样一组数[ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ],如果我们以步长为5开始进行排序,我们可以通过将这列表放在有5列的表中来更好地描述算法,这样他们就应该看起来是这样:

13 14 94 33 82
25 59 94 65 23
45 27 73 25 39
10
然后我们对每列进行排序:

10 14 73 25 23
13 27 94 33 39
25 59 94 65 82
45
将上述四行数字,依序接在一起时我们得到:[ 10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45 ]。这时10已经移至正确位置了,然后再以3为步长进行排序:

10 14 73
25 23 13
27 94 33
39 25 59
94 65 82
45
排序之后变为:

10 14 13
25 23 33
27 25 59
39 65 73
45 94 82
94
最后以1步长进行排序(此时就是简单的插入排序了)。

def shell_sort(ary):
    n = len(ary)
    gap = round(n/2)       #初始步长 , 用round四舍五入取整
    while gap > 0 :
        for i in range(gap,n):        #每一列进行插入排序 , 从gap 到 n-1
            temp = ary[i]
            j = i
            while ( j >= gap and ary[j-gap] > temp ):    #插入排序
                ary[j] = ary[j-gap]
                j = j - gap
            ary[j] = temp
        gap = round(gap/2)                     #重新设置步长
    return ary

归并排序(递归拆分数组,然后合并)

def merge_sort(ary):
    if len(ary) <= 1 : return ary
    num = int(len(ary)/2)       #二分分解
    left = merge_sort(ary[:num])
    right = merge_sort(ary[num:])
    return merge(left,right)    #合并数组

def merge(left,right):
    '''合并操作,
    将两个有序数组left[]和right[]合并成一个大的有序数组'''
    l,r = 0,0           #left与right数组的下标指针
    result = []
    while l<len(left) and r<len(right) :
        if left[l] < right[r]:
            result.append(left[l])
            l += 1
        else:
            result.append(right[r])
            r += 1
    result += left[l:]
    result += right[r:]
    return result

快速排序

def quick_sort(arry):
    return qsort(arry,0,len(arry)-1)

def qsort(arry,left,right):#[3,2,1,4]
    if left >= right:
        return arry
    key = arry[left]#3
    lp = left#0
    rp = right#3
    while lp < rp:
        while arry[rp] >= key and lp < rp:
            rp -=1
        while arry[lp] <= key and lp <rp:
            lp +=1
        arry[lp],arry[rp] = arry[rp],arry[lp]
    arry[left],arry[lp] = arry[lp],arry[left]
    qsort(arry,left,lp-1)
    qsort(arry,rp+1,right)
    return arry
if __name__ == '__main__':
    disorder_arry  = [3,2,1,4]
    order_arry = quick_sort(disorder_arry)
    print(order_arry)

堆排序

def heap_sort(ary) :
    n = len(ary)
    first = int(n/2-1)       #最后一个非叶子节点
    for start in range(first,-1,-1) :     #构造大根堆
        max_heapify(ary,start,n-1)
    for end in range(n-1,0,-1):           #堆排,将大根堆转换成有序数组
        ary[end],ary[0] = ary[0],ary[end]
        max_heapify(ary,0,end-1)
    return ary


#最大堆调整:将堆的末端子节点作调整,使得子节点永远小于父节点
#start为当前需要调整最大堆的位置,end为调整边界
def max_heapify(ary,start,end):
    root = start
    while True :
        child = root*2 +1               #调整节点的子节点
        if child > end : break
        if child+1 <= end and ary[child] < ary[child+1] :
            child = child+1             #取较大的子节点
        if ary[root] < ary[child] :     #较大的子节点成为父节点
            ary[root],ary[child] = ary[child],ary[root]     #交换
            root = child
        else :
            break
posted @ 2019-09-21 15:35  二进制的弗洛伊德  阅读(2726)  评论(0编辑  收藏  举报