七大排序算法,你都学会了吗?插入排序、归并排序、堆排序、快速排序、计数排序、基数排序、桶排序

 插入排序:

"""
encoding:utf-8
插入排序的工作方式像许多人排序一手扑克牌。
开始时,我们的左手为空并且桌子上的牌面向下。
然后,我们每次从桌子上拿走一张牌并将它插入左手中正确的位置。
为了找到一张牌的正确位置,我们从右到左将它与已在手中的每张牌进行比较。
拿在左手上的牌总是排序好的,原来这些牌是桌子上牌堆中顶部的牌。
插入排序是指在待排序的元素中,假设前面n-1(其中n>=2)个数已经是排好顺序的,
现将第n个数插到前面已经排好的序列中,然后找到合适自己的位置,使得插入第n个数的这个序列也是排好顺序的。
按照此法对所有元素进行插入,直到整个序列排为有序的过程,称为插入排序
时间复杂度:最好情况O(N)  最坏情况:O(N^2)
空间复杂度:O(1)
2021-11-19-0:11
"""
import random
def insertSort(list_1):
    for i in range(1,len(list_1)): #从第二个数开始,依次与前面的数比较
            temp = list_1[i]       #用一个临时变量保存需要插入的值
            j=i
            while(j>0 and list_1[j-1]>temp): #循环,直至找到需要插入的位置j
                list_1[j] = list_1[j-1]
                j-=1
            list_1[j] = temp        #插入
if __name__=='__main__':
    list_1 = [random.randint(0,100) for i in range(20)]
    insertSort(list_1)
    print(list_1)

归并排序:

"""
encoding:utf-8
归并排序采用分而治之的原理:
一、将一个序列从中间位置分成两个序列;
二、在将这两个子序列按照第一步继续二分下去;
三、直到所有子序列的长度都为1,也就是不可以再二分截止。这时候再两两合并成一个有序序列即可。
最坏、最佳、平均情况下归并排序时间复杂度均为o(nlogn)
"""
import random
def merge(left,right):
    i,j=0,0
    list_1=[]
    while i<len(left) and j<len(right):
        if left[i]<right[j]:
            list_1.append(left[i])
            i+=1
        else:
            list_1.append(right[j])
            j+=1
    if i==len(left):
        list_1.extend(right[j:])
    else:
        list_1.extend(left[i:])
    return list_1
def merge_Sort(list_1):
    if len(list_1)<=1:
        return list_1
    mid=len(list_1)//2
    left=merge_Sort(list_1[:mid])
    right=merge_Sort(list_1[mid:])
    return merge(left,right)
if __name__=='__main__':
    list_1=[random.randint(0,100) for i in range(20)]
    print(merge_Sort(list_1))

堆排序:

"""
我们从最后一个非叶子结点处开始调整。最后一个非叶子结点是最后一个叶子结点的父结点。
若父结点的下标为i ,那么左孩子结点下标为i × 2 + 1,
右孩子结点下标为i × 2 + 2。
设元素列的长度为
N,因为下标从0开始,所以最后一个叶子结点的下标是N - 1。
分两种情况:第一种是最后一个叶子结点是左孩子结点,那么
N - 1 = i × 2 + 1,即
i = N / 2 - 1
第二种情况是最后一个结子结点是右孩子结点(此时N是奇数)
那么N - 1 = i × 2 + 2,即
i = (N - 1) / 2 - 1 = N / 2 - 1(向下取整)
综上,最后一个非叶子结点的下标是
N / 2 - 1,即(N-2)//2
时间复杂度:O(nlogn)
"""

def max_heapify(heap,heapSize,root): #维护堆性质(O(logn))
    left=2*root+1
    right=left+1
    max=root
    if left<heapSize and heap[max]<heap[left]: #若左孩子结点存在,且左孩子结点大于目前最大结点heap[max]
        max=left
    if right<heapSize and heap[max]<heap[right]: #若右孩子结点存在,且右孩子结点大于目前最大结点heap[max]
        max=right
    if max!=root: #若根结点不是最大结点
        heap[max],heap[root]=heap[root],heap[max]
        max_heapify(heap,heapSize,max) #递归,维护子树
def build_max_heap(heap): #建立最大堆 O(n)
    heapSize=len(heap)
    for i in range((heapSize-2)//2,-1,-1): #因为索引从0开始,最后一个叶子结点的父结点下标为(heapSize-2)//2
        max_heapify(heap,heapSize,i)
def heap_sort(heap):
    build_max_heap(heap) #建立最大堆,列表第一个元素是最大的
    for i in range(len(heap)-1,-1,-1):
        heap[i],heap[0]=heap[0],heap[i] #将列表第一个元素与最后一个元素交换
        max_heapify(heap,i,0) #每交换一次,堆长度减一,所以是长度变为i
                              #O(n)+O(nlogn)=O(nlogn)
import random
if __name__=='__main__':
    heap=[random.randint(0,100) for i in range(20)]
    heap_sort(heap)
    print(heap)

快速排序:

"""
encoding:utf-8
计数排序是一种非常快捷的稳定性强的排序方法,时间复杂度O(n+k),其中n为要排序的数的个数,k为要排序的数的组大值。
计数排序对一定量的整数排序时候的速度非常快,一般快于其他排序算法。但计数排序局限性比较大,只限于对整数进行排序。
计数排序是消耗空间复杂度来获取快捷的排序方法,其空间复杂度为O(K)同理K为要排序的最大值。

计数排序的基本思想为一组数在排序之前先统计这组数中其他数小于这个数的个数,则可以确定这个数的位置
需要三个数组,假设输入是一个数组A[0..n-1],A.length=n。我们还需要两个数组:B[0..n-1]存放排序的输出,C[0..k]提供临时存储空间。
"""
def countingSort(A,k):
    A_length=len(A)
    C=[0 for i in range(k+1)]
    B=[0 for i in range(A_length)]
    for i in range(A_length):
        C[A[i]]+=1
    for i in range(1,len(C)):
        C[i]=C[i]+C[i-1]
    for i in range(A_length-1,-1,-1):
        B[C[A[i]]-1]=A[i]  #因为数组下标从0开始,所以减一
        C[A[i]]-=1
    return B
import random
if __name__=="__main__":
    A=[random.randint(0,100) for i in range(20)]
    print(countingSort(A,max(A)))

基数排序:

"""
encoding:utf-8
时间复杂度:O(n).

基本思路:两个数比较大小,我们的直观感觉是先比较高位,若相同则比较低位。但是这样做需要记录额外的数据,浪费空间。
而基数排序则是先比较低位,再比较高位。通过各个位的比较进行排序,如果数组元素最大有N位,则总共需要N次排序。
注意:按位排序必须是稳定排序,所以在这我选择了计数排序。
"""
def radix_sort(A):
    place=1
    while max(A)>=10**place:
        place+=1
    B={}
    for i in range(place):
        for j in range(10):
            B[j]=[]
        for num in A:
            radix=int(num/(10**i)%10)
            B[radix].append(num)
        j=0
        for key in B:
            for num in B[key]:
                A[j]=num
                j+=1
    return A
import random
if __name__=="__main__":
    A=[random.randint(0,100) for i in range(20)]
    print(radix_sort(A))

桶排序:

"""
encoding:utf-8
1.设置一个定量的数组当作空桶子。
2.寻访序列,并且把项目一个一个放到对应的桶子去。
3.对每个不是空的桶子进行排序。
4.从不是空的桶子里把项目再放回原来的序列中。

平均情况下时间代价为 O(n)
期望运行时间代价为 Θ(n)
最坏情况下时间代价为 Θ(n^2),可以通过修改算法使其在保持平均情况为线性时间代价的同时,最坏时间代价为 Θ(nlgn)
"""
#只考虑n>=10的情况,且数值的范围在[0,1]
def bucket_sort(A):
    n=len(A)
    B={}
    for i in range(10):
        B[i]=[]
    for i in range(n):
        B[int(10*A[i])].append(A[i])
    for key in B:
        B[key].sort()
    i=0
    for key in B:
        for num in B[key]:
            A[i],i=num,i+1
import random
if __name__=='__main__':
    A = [random.random() for i in range(30)]
    bucket_sort(A)
    print(A)

如有错误,还望指正!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值