常用排序算法的python实现

总是不能在网络上找到完整正确简洁的排序算法的python写法, 还是自己写一篇作为归纳.
下列方法都经过测试
测试方法:

import random
#生成随机数组
a = [random.randint(0,1000) for _ in range(100)]
#执行排序
sortfunc(a)
#判断结果
bool(a == sorted(a)) 
#若为降序排序则为bool(a == sorted(a,reverse=True))

1.选择排序

def selectsort(a):
    for i in range(len(a)-1):
        for j in range(i+1,len(a)):
            if a[j] < a[i]:
                a[i],a[j] = a[j],a[i]

记忆点:遇到比i位小的数,交换两个值,每一趟找出第i小的数
时间复杂度:O(n*n)

2.插入排序

2018.12.15 更新
根据算法导论重新写了插入排序,效率更高

版本1

def inssort(a):
    for i in range(1,len(a)):
        for j in range(i,0,-1):
            if a[j-1] > a[j]:
                a[j-1],a[j] = a[j],a[j-1]
            else:
                break

版本2

def inssort(a):
    for i in range(1,len(a)):
        key = a[i]
        j = i-1
        while j >= 0 and a[j] > key:
            a[j+1] = a[j]
            j -= 1
        a[j+1] = key

自写版本

def inssort(a):
    for i in range(1,len(a)):
        key = a[i]
        for j in range(i-1,-1,-1):
            if a[j] > key:
                a[j],a[j+1] = a[j+1],a[j]

时间复杂度:O(n*n)

3.冒泡排序

def bubble(a):
    for i in range(len(a),0,-1):
    	swapped = False
        for j in range(i-1):
            if a[j+1] < a[j]:
                a[j],a[j+1] = a[j+1],a[j]
                swapped = True
        if not swapped:
            break

时间复杂度: O(n*n)
记忆点:

  1. 冒泡第i趟可以确保最左(或最右,取决于实现)i个值为最正确顺序;
  2. 加入swapped可以判断最好的情况,即数组已经排好序,时间复杂度降为O(n)

4.快速排序

def qsort(a,l,r):
    if l < r:
        p = a[r]
        i = l - 1
        for j in range(l,r):
            if a[j] <= p:
                i += 1
                a[i],a[j] = a[j],a[i]
        i += 1
        a[i],a[r] = a[r],a[i]
        qsort(a,l,i-1)
        qsort(a,i+1,r)

python快速排序的各种实现方法中有更详细一些的表述.
时间复杂度: O(nlogn),在每次选到的主元(pivot)都为当前数组最大或最小值时,算法退化到O(n*n).

5.归并排序

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

def mergesort(lists):
    if len(lists) <= 1:
        return lists
    mid = len(lists)//2
    left = mergesort(lists[:mid])
    right = mergesort(lists[mid:])
    return merge(left,right)

内部排序版本(在原数组上排序):

def merge(lst, l,mid,r):
    left = lst[l:mid+1]
    right = lst[mid+1:r+1]  
    k = l
    while left and right:
        if left[0] <= right[0]:
            lst[k] = left.pop(0)
        else:
            lst[k] = right.pop(0)
        k += 1
    tail = left if left else right
    for n in tail:
        lst[k] = n
        k += 1
    
def mergesort(lst,l,r):
    if l < r:
        mid = (l + r-1)//2
        mergesort(lst,l,mid)
        mergesort(lst,mid+1,r)
        merge(lst,l,mid,r)

6.堆排序

def adjust_heap(a,i,size):
    if i <= (size-2)//2:
        l = 2*i + 1 #左结点
        r = 2*i + 2 #右结点
        m = i
        if l < size and a[l] > a[m]:
            m = l
        if r < size and a[r] > a[m]:
            m = r
        if m != i:
	        #若子节点比根节点大,则交换结点
            a[m],a[i] = a[i],a[m]
            #交换后不能保证位于子节点位置的原本的"根节点"符合堆性质,继续调整
            adjust_heap(a,m,size)

def build_heap(a):
    size = len(a)
    #倒数第一个下标为size-1,((size-1)-1)//为最后一个非叶节点
    for i in range((size-2)//2,-1,-1):
        adjust_heap(a,i,size)

def heapsort(a):
    size = len(a)
    #建堆
    build_heap(a)
    for i in range(size-1,0,-1):
	    #大顶堆性质:a[0]必为每次排序的最大值,将其放到数组后面
        a[0],a[i] = a[i],a[0]
        adjust_heap(a,0,i)

7.计数排序

def count_sort(a):
    c = [0 for _ in range(1000)]
    #若对于未知范围的数据 c = [0 for _ in range(max(a))]
    for n in a:
        c[n] += 1
    res = []
    for i,n in enumerate(c):
        for k in range(n):
            res.append(i)
    return res
  1. 希尔排序
def shellsort(num):
    step = len(num)//2
    while step > 0:
        for i in range(step, len(num)):
            while i >= step and num[i-step] > num[i]:
                num[i], num[i-step] = num[i-step], num[i]
                i = i - step
        step = step//2
    return

时间复杂度: 对于N个范围在(0,K)的数,第一遍计数复杂度为O(n),第二遍重组目标数组复杂度为O(K),总时间复杂度为O(n+k).

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值