稳定的排序

排序

  • 接前面
  • 分类
    • 插入排序
      • 希尔排序改造
    • 选择排序
      • 堆排序改造
    • 交换排序
      • 非递归快速排序
    • 分配排序
      • 基数分配排序改造
    • 归并排序
      • 归并排序改造
    • 点数排序
  • 测试

接前面

排序——万亿数量级里有的排序算法很快,有的却比较慢。上帝在打开一扇牗的时候会关上一樘门,这扇门就是稳定性。书上用的是 49 ′ {49}' 49,这里用二元组。看排序后(5,1), (5,4),(5,12)的位置会不会发生变化。
test=[(5,1), (11,2),(3,3), (5,4), (56,5), (65,6), (1,7), (8,8), (2,9), (6,10), (7,11), (5,12)]

在这里插入图片描述书上的例子

分类

插入排序

直接插入排序、二分法插入排序、表插入排序和希尔排序都是插入排序。只有希尔排序是不稳定的,其他都是稳定的。

希尔排序改造

    def shellSort(nums):#希尔步长缩小后移插入排序,不稳定
        n = len(nums)
        gap = n // 3
        while gap > 0:#n/3,每次缩小1/3,
            for i in range(gap, n):#每次加大
                anchor = nums[i]
                j = i
                while j >= gap and nums[j - gap][0] > anchor[0]:#从搜索一个到全部,
                    nums[j] = nums[j - gap]
                    j -= gap
                nums[j] = anchor
            #gap = gap // 2
            gap = (gap - 1)//3
        return nums

这里用的步长是 1 3 \frac{1}{3} 31,据说这样的效果更好。nums[j - gap][0] > anchor[0]比较元组的第一个元素。

选择排序

直接选择排序和堆排序。都不稳定。直接选择排序指定i与剩下所有的j比,确定i的位置,选小的时候把后面大的相同的顺序打乱了。大堆选择排序每次 2 ∗ i d x + 1 2*idx + 1 2idx+1跳着比较也会打乱顺序。

堆排序改造

    def heapify(a, idx, m):
        left = 2*idx + 1
        right = 2*idx + 2
        if left < m and a[left][0] > a[idx][0]:
            largest = left
        else:
            largest = idx
        if right < m and a[right][0] > a[largest][0]:
            largest = right
        if largest != idx:
            a[idx], a[largest] = a[largest], a[idx]
            heapify(a, largest, m)
    def buildheap(a):
        n = len(a)
        for i in range((n//2) - 1, -1, -1):#从后往前
            heapify(a, i, n)
    def heapS(a):#不稳定,堆选择排序
        buildheap(a)
        for i in range(len(a) - 1, 0, -1):
            a[0], a[i] = a[i], a[0]
            heapify(a, 0, i)

交换排序

起泡排序(稳定)、快速排序(不稳定)。两两比较,交换不满足顺序要求的两个值,直到全部满足为止。

非递归快速排序

    def quick(alist):#非递归
        assert len(alist) >= 2
        q = []
        q.append((0,len(alist)-1))
        while q:
            start, end = q.pop()
            mid = alist[start]#mid is the pivot of the partition
            low = start
            high = end
            while low < high:
                while low < high and alist[high][0] >= mid[0]:
                    high -= 1
                alist[low] = alist[high]
                while low < high and alist[low][0] < mid[0]:
                    low += 1
                alist[high] = alist[low]
            alist[low] = mid
            if low - 1 > start:          
                q.append((start, low - 1))
            if low + 1 < end:
                q.append((low + 1, end))  

分配排序

基数排序,把排序码分解成若干部分排序。稳定

基数分配排序改造

    def radixSort(L, r=10):#分配排序,基数排序,稳定
        k = 10#int(math.ceil(math.log(max(L), r)))
        b = [[] for i in range(r)]
        for i in range(1, k+1):#循环位数次
            for j in L:#循环n次
                b[int(j[0] / (r ** (i-1)) % r)].append(j)
            del L[:]#分桶后清空list L
            for z in b:
                L += z
                del z[:]#l再装桶后,清除临时数组
        return -1 

归并排序

稳定

归并排序改造

    def merge(L, R):#稳定
        '''L and R merge together
        '''
        iL, iR = 0, 0
        result = []
        while iL < len(L) and iR < len(R):
            if L[iL][0] <= R[iR][0]:
                result.append(L[iL])
                iL += 1
            else:
                result.append(R[iR])
                iR += 1
        result += L[iL:]
        result += R[iR:]
        return result
    def merge_sort(alist):#T(n)=2T(n/2)+n的解为T(n)=O(nlogn)
        if len(alist) <= 1:
            return alist
        #Int is a decimal truncation method, not rounding, int (x+0.5) can be rounded. 
        m = int(len(alist) // 2)
        L = merge_sort(alist[:m])
        R = merge_sort(alist[m:])
        #from two to len(alist) to return merge_sort 
        return merge(L, R)        

L[iL][0] <= R[iR][0]比较元组的第一个元素。

点数排序

稳定

测试

    test=[(5,1), (11,2),(3,3), (5,4), (56,5), (65,6), (1,7), (8,8), (2,9), (6,10), (7,11), (5,12)]
    shellx = test.copy()
    print("希尔插入排序",shellSort(shellx))
    heapx = test.copy()
    heapS(heapx)
    print("大堆选择排序",heapx)
    quickx = test.copy()
    quick(quickx)
    print("快速交换排序",quickx)    
    radixx = test.copy()
    radixSort(radixx)
    print("基数分配排序",radixx)     
    mergex = test.copy()
    print("归并稳定排序",merge_sort(mergex))   
希尔插入排序 [(1, 7), (2, 9), (3, 3), (5, 4), (5, 1), (5, 12), (6, 10), (7, 11), (8, 8), (11, 2), (56, 5), (65, 6)]
大堆选择排序 [(1, 7), (2, 9), (3, 3), (5, 1), (5, 12), (5, 4), (6, 10), (7, 11), (8, 8), (11, 2), (56, 5), (65, 6)]
快速交换排序 [(1, 7), (2, 9), (3, 3), (5, 1), (5, 12), (5, 4), (6, 10), (7, 11), (8, 8), (11, 2), (56, 5), (65, 6)]
基数分配排序 [(1, 7), (2, 9), (3, 3), (5, 1), (5, 4), (5, 12), (6, 10), (7, 11), (8, 8), (11, 2), (56, 5), (65, 6)]
归并稳定排序 [(1, 7), (2, 9), (3, 3), (5, 1), (5, 4), (5, 12), (6, 10), (7, 11), (8, 8), (11, 2), (56, 5), (65, 6)]

从排序后(5,1), (5,4),(5,12)的位置看,希尔插入排序、堆选择排序和快速交换排序不稳定。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值