算法基础:排序(一)——选择排序、插入排序、Shell排序——Python实现

排序问题形式化定义:
输入:由n个数构成的一个序列{a1,a2,…,an}
输出:对输入序列的一个排列{a1’,a2’,…,an’},使得a1’<=a2’<=…<=an’

在计算机科学中,排序是一种基本操作,它是很多程序中会调用到的一个方法。不同的排序算法在不同条件下拥有各自的优劣,掌握各种排序算法的特点,不仅有助于我们编写特定程序时的选用,而且可以帮助我们理解算法复杂度的计算。


1. 洗牌(Knuth Shuffle)

如何洗牌,即打乱一个序列,Knuth洗牌算法可以做到遍历一遍数组便将其完全打乱,即时间复杂度O(n)。

import random

# random、numpy.random模块都有shuffle方法,这里顺便自己实现一下
class Shuffle:

    @staticmethod
    def knuthShuffle(a):
        for i in range(0, len(a)): # 从左到右遍历数组
            r=random.randint(0,i) # 生成一个0-i之间的随机数
            a[i], a[r] = a[r], a[i] # 交换

2. 排序基类

这里的排序基类定义了各种排序算法需要用到的操作:比较大小、交换等,这样可以使排序算法的代码更加易读。

class Sort:

    def sort(self, a):
        pass

    @staticmethod
    def less(small, big):
        return small < big

    @staticmethod
    def exch(a, i, j):
        a[i], a[j] = a[j], a[i]

    def isSorted(self, a):
        for i in range(1,len(a)):
            if self.less(a[i], a[i-1]):
                return False
        return True

3. 选择排序

依次对每一个元素a[i],找到右边所有元素中最小的一个min{a[i+1],…,a[N-1]},与该元素交换。


class Selection(Sort):

    def sort(self, a):
        # 依次对每一个元素a[i]
        for i in range(0,len(a)):
            # 找到右边所有元素中最小的一个min{a[i + 1], ..., a[N - 1]}
            mini = i
            for j in range(i+1,len(a)):
                if self.less(a[j],a[mini]):
                    mini = j
            #与该元素交换
            self.exch(a,i,mini)

4. 插入排序

从左到右依次将每一个元素a[i],插入到左边有序数组{a[0],…,a[i-1]}中合适的位置,使a[0]…a[i]依然有序。
遍历+交换: 时间复杂度O(N^2)。
最好情况:对有序数组O(N),N-1次比较,0次交换;
最坏情况:逆序数组O(N^2),N*(N-1)/2次比较,N*(N-1)/2次交换


class Insertion(Sort):

    def sort(self, a):
        for i in range(1,len(a)):
            for j in range(i,0,-1):
                if self.less(a[j],a[j-1]):
                    self.exch(a,j,j-1)
                else:
                    break

5. 冒泡排序

冒泡排序与插入排序类似,都是相邻两元素作交换。


class Bubble(Sort):

    def sort(self, a):
        sortedflag=True
        for i in range(0,len(a)):
            for j in range(i,len(a)): #冒泡排序每一趟都会将最小的元素换到最前面
                if self.less(a[j],a[i]):
                    self.exch(a,j,i)
                    sortedflag=False
            if sortedflag: # 若第一趟无元素交换,说明数组有序,直接return
                print("already sorted!")
                return

6. 希尔排序

希尔排序是一种基于插入排序的快速的排序算法,其思想是使数组中任意间隔h的元素都是有序的,目的是为了减少元素的移动距离


class Shell(Sort):

    def sort(self, a):
        h=1
        while h<len(a)/3:
            h=3*h+1
        while h>=1:
            for i in range(h,len(a)):
                for j in range(i,h-1,-h):
                    if self.less(a[j],a[j-h]):
                        self.exch(a,j,j-h)
            h=int(h/3)

7. 算法性能比较

经过多次测试,四种初级排序算法用时平均为10:12:15:9。
冒泡排序时间最长,Shell最短但与选择排序不相上下。
通过运行时间我们也可以大致看出,数组个数由1000增至10000,用时增至原来的100倍,由此也可以推出以上初级排序算法的时间复杂度为O(n^2)。

import time

l = [i for i in range(10000)] # 生成一个0-9999的列表
Shuffle.knuthShuffle(l) # 洗牌
print(l)
l1,l2,l3,l4=list(l),list(l),list(l),list(l)

selesort=Selection()
start=time.time()
selesort.sort(l1)
end=time.time()
print("Selection sort running time:",end-start,l1)

insersort = Insertion()
start = time.time()
insersort.sort(l2)
end = time.time()
print("Insertion sort running time:", end - start, l2)

bubsort = Bubble()
start = time.time()
bubsort.sort(l3)
end = time.time()
print("Bubble sort running time:", end - start, l3)

shellsort = Shell()
start = time.time()
selesort.sort(l4)
end = time.time()
print("Shell sort running time:", end - start, l4)

1000个数排序用时比较
10000个数排序用时比较

(参考资料:《算法(第四版)》)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值