11种排序算法 python实现(冒泡、选择、插入、快速、堆、希尔、归并、计数、二分法、桶、基数)

11种排序算法 python实现

冒泡,选择,插入,快速,堆,希尔,归并,二分法(基于比较的)
计数, 桶,基数(基于非比较的)

  • 排序算法时间复杂度
算法最好情况最坏情况平均情况空间复杂度稳定性
冒泡n^2n^2n^21稳定 (小于或者大于的才会交换,等于 不交换))
选择n^2n^2n^21不稳定
插入nn^21稳定
快速nlgn递归实现 基准 (以第一个元素为基准)不稳定
建立堆,调整 调整 n 次不稳定
希尔分组插入排序 增量 减半直到增量为1不稳定
归并平均分成左右两部分、排序、再合并 递归调用稳定
计数n+k,k为数组中最大的数
基数
二分插入
  • 排序算法稳定性
  • 在这里插入图片描述

1. 冒泡排序

冒泡排序的基本思想是通过与相邻元素的比较和交换,每次将最大元素放到数组尾部。整个过程类似于水中气泡的上升。
比较次数:为n-1,n-2,…, 1
时间复杂度 n^2

 def sort_1(tinput):   ## 冒泡排序
        length =len(tinput)
        if length<=0:
            return None
        if length ==1:
            return tinput
        
        for i in range(length):
            for j in range(length-i-1):  #每次将最大的放最后
                if tinput[j]>tinput[j+1]:  #将大的交换到后边
                    tinput[j],tinput[j+1]=tinput[j+1],tinput[j]
                else:
                    pass
        return tinput

2.选择排序

选择排序的基本思想也是比较和交换,但选择排序是通过对整体的选择。每次找出剩余数组中最小的元素与第一个元素交换。
时间复杂度为 n^2,与冒泡排序相比,交换次数减少。

def sort_2(self,tinput):  #选择排序
        length =len(tinput)
        if length<=0:
            return None
        if length ==1:
            return tinput
        for i in range(length):   #找出最小元素的下标
            min_index =i
            for j in range(i+1,length):
                if tinput[j]<tinput[min_index]:
                    min_index =j
                else:
                    pass
            tinput[i],tinput[min_index] =tinput[min_index],tinput[i]
        return tinput

3.插入排序

通过比较找到合适的位置,然后插入元素,从后往前比
将数组分为有序,无序两部分,每次将无序中的一个元素插入有序部分中。
最好情况,比较 n-1次
最坏情况1,2,……,n-1 .

  def sort_3(tinput): #插入排序
        length =len(tinput)
        if length<=0:
            return None
        if length ==1:
            return tinput
        relist = [tinput[0]]  #一个元素有序   
        for i in range(1,length):
            for j in range(len(relist)):      #找到插入的位置
                if tinput[i] < relist[j]:
                    break
                if tinput[i]== relist[j]:
                    j+=1
                    break
                else:
                    pass
            if j == len(relist) - 1:
                relist.append(tinput[i])  ##加到末尾   ,j的最大值为len(relist)-1
            else:
                relist.insert(j, tinput[i])
        return relist

4.快速排序(在实际应用中表现最好的算法)

快速排序的思想来自于冒泡排序,冒泡排序是通过相邻元素的比较和交换把最小的冒泡到最顶端,而快速排序是通过和基准数比较,交换小数和大数,这样一来不仅把小数冒泡到上面同时也把大数沉到下面。
每次都需要找一个基准数,从两边扫描。
递归,不稳定。
时间复杂度:nlgn。

def QuickSort(tinput,start,end):
     i = start
     j = end
     if i >=j:
         return
     partion = tinput[start]
     while i<j:
         while i<j and tinput[j]>= partion:  #往左扫描,找到第一个比partion小的数
             j-=1
         tinput[i] = tinput[j]                #此时 i 的值以放入 partion中
         while i<j and tinput[i]<=partion:  #网友扫描,找到第一个比partion大的值,
             i+=1
         tinput[j]= tinput[i]                    #同上
     tinput[i]= partion                     #将partion 放入它应该在的位置
     QuickSort(tinput,start,i)
     QuickSort(tinput,i+1,end)
     return tinput

5.堆排序(升序(大顶堆),降序(小顶堆))

相关知识 :完全二叉树、堆、父子节点的索引关系
需要解决的两个问题
1,如何建立一个堆
2,删除堆顶元素后,如何调整堆
思路
1,先写出如何调整堆,
2,从最后一个根节点开始调整,直至第一个元素,调整完,大顶堆 就建立好了
3、将第一个元素(即堆顶元素(最大的元素))与最后一个元素交换,即(将最大元素放到末尾),然后调整堆 直至最后堆的大小为1

def heap_adjust(tinput,start,end):#调整最大堆
    root = start
    length = len(tinput)
    son = int(2*root +1 ) ##左孩子
    while son <= end:
        if son+1<=end and tinput[son]<tinput[son+1]:   #找出左右孩子中较大的那个
            son+=1
        if tinput[son]>tinput[root]:  #如果孩子大于父节点 交换
            tinput[son],tinput[root]=tinput[root],tinput[son]   #交换
            root = son
            son  = 2*root+1
        else:
            break        ##如果父节点已经是大的,说明调整完整
def heap_sort(tinput):
    lastroot = (len(tinput)-1-1)//2 #从最后一个根节点开始调整,即建立大顶堆
    while lastroot >=0:
        heap_adjust(tinput,lastroot,len(tinput)-1)
        lastroot-=1
    #大顶堆建立完成

    lastnode = len(tinput)-1
    while lastnode >=0:
        tinput[0],tinput[lastnode] = tinput[lastnode],tinput[0]  #将最后一个元素与第一个元素(即堆顶元素)交换
        lastnode-=1
        heap_adjust(tinput,0,lastnode)       #调整堆
    return tinput

6.希尔排序

希尔排序又称缩小增量排序,是插入排序的高阶实现。
1设置一个初始增量gap(一般为序列长的一半),将序列分为gap个子序列,对子序列进行插入排序,
2缩小增量,直至增量缩小为1,此时子序列就是整个序列,再进行一次直接插入排序即可

def ShellSort(tinput):
    length = len(tinput)
    gap = length//2   ##设置增量一般为序列长度的一半
    while gap >0:
        for  i in range(gap,length):
            while i >= gap and tinput[i]<tinput[i-gap]:
                tinput[i],tinput[i-gap]= tinput[i-gap],tinput[i]      #在子序列中找要插入的位置
                i = i-gap
        gap //=2   #增量减半
    return tinput

7.归并排序

采用递归分治的思想,稳定,速度仅次于快排
1.合并两个有序序列
2.将原序列分为左右两个部分,对两个部分递归排序;
合并两个部分

def merge(left,right):    ##合并两个有序的序列
    i=0
    j=0
    list = []
    while i< len(left) and j<len(right):
        if right[j] < left[i]:      #右边的数小,放入数组,指针右移
            list.append(right[j])
            j+=1
        else:
            list.append(left[i])   #
            i+=1
    list.extend(left[i:])  #将剩余部分 放入列表
    list.extend(right[j:])
    return list
def mergeSort(tinput):
    if len(tinput)<=1:
        return tinput
    num = len(tinput)//2
    left = mergeSort(tinput[:num])  #将左边部分排序
    right = mergeSort(tinput[num:])  #将右边部分排序
    list_ = merge(left,right) #合并左右两个部分
    return  list_

8.计数排序

计数排序是一种非基于比较的算法,计数排序的时间复杂度为n+k,k为数组中最大的数,但计数排序需要满足一定的前提条件,即待排序的数要满足一定的范围的整数,而且需要花费大量的空间。
算法示例
1.待排序序列 [1,3,1,3,4,3,3,5,2] 在 0到5的范围
2. 设置数组count = [0,0,0,0,0,0],即下标为0到5的数组
3.遍历元素组,元素对应位置加1,完成后count =[0,2,1,4,1,1]
4.根据count数组输出排序后的数组 [1,1,2,3,3,3,3,4,5]

def CountSort(tinput): #适用于一定范围的整数排序
    max = tinput[0]
    for i in tinput: # 找出最大值
        if i>max:
            max = i
    count = [0 for x in range(max+1)]  #创建一个下标最大为max 的数组
    for i in tinput:  #计数,每一个元素出现的次数
        count[i]+=1
    List1=[]
    for i in range(len(count)):
        if count[i] !=0:   #出现次数不为0
            for j in range(count[i]):
                List1.append(i)
    return List1

9.桶排序

非比较的算法,当待排序序列均匀分配时,时间复杂度为n,典型应用,高考分数。
1.创建M个桶
2.将序列按照每种映射函数映射到桶中
3.对每个桶中的子序列进行排序
4.从头到尾遍历每个桶

def BucketSort(tinput):
    bucket =[[] for i in range(10)]   #建立10个桶
    for i in tinput:
        index = i//10
        if index<=9:
            bucket[index].append(i)    #将元素放入桶中
        else:
            bucket[9].append(i)
    for i in range(10):   #对每个桶中的元素,进行排序
        bucket[i] = QuickSort(bucket[i],0,len(bucket[i])-1)
    list =[]
    for i in bucket:
        if i:
            list.extend(i)
    return list

10.基数排序

一种借助多关键字排序的思想。
通过多次分配和收集实现关键字排序,一般情况下,关键字优先级高的先进行分配和收集。
借助桶
对于数字排序,LSD(适用于位数少的,先从低位开始),MSD(适用于位数多的,先从高位开始)

def RadixSort(tinput):
    if len(tinput)<=0:
        return
    for i in range(1,6):   #依次取个、十,百,千,万作为关键字
        bucket = [[] for m in range(10)]
        ii = 10**i
        print(ii)
        for j in tinput :    #分配
            index = (j//ii)%10   #去每一个数的相应位数上的数
            bucket[index].append(j)
        tinput =[]
        for k in bucket:   #收集
            if k:
                tinput.extend(k)
    return tinput

11.二分法排序

二分法插入排序是在插入排序的基础上,使用二分法查找将元素插入的方法,二分插入排序的原理较为简单,但是二分边界的确定以及范围比较的实现较为繁琐。
基本原理:(升序)
1.将元素依次放入有序序列中
2.取出待排序元素,与有序序列的前半段进行比较
3.缩小有序序列范围,进一步划分比较,直至范围内仅有1或2个数字
4.将插入值与范围进行比较
3.重复实现升序
实现过程:外层循环控制循环次数,中层循环实现有序排列,内层循环实现查找插入。

最好情况:每次中间的刚好是插入位置,比较 n-1 稳定
最坏情况 :lg1+lg2+lg3+……+lg(n-1) nlgn

def BinaryInsertSort(tinput):
    length = len(tinput)
    if length<=1:
        return
    for i in range(1,length):
        left = 0
        right = i-1
        while left <right:    #二分查找插入位置
            mid = (left+right)//2
           # print(mid," ",i)
            if mid == left:  # 边界值已确定
                break
            if tinput[mid] == tinput[i]:   ##如果与中间元素相等
                break
            if tinput[mid] <tinput[i]:
                left=mid
            else:
                right = mid                  #left指针所指的位置,就是要插入的位置
        #先确定是否因为找到相同值而提前终止
        if tinput[i] == tinput[(left+right)//2]:
            tinput.insert((left+right)//2,tinput[i])
            tinput.pop(i+1)
        else:
            if left == right:#只有一个元素
                if tinput[left]<tinput[i]:
                    pass
                else:
                    tinput[left],tinput[i]=tinput[i],tinput[left]
            if left<right: #有两个元素
                if tinput[right]<tinput[i]:
                    tinput.insert(right+1,tinput[i])
                else:
                    if tinput[left]<tinput[i]:
                        tinput.insert(right,tinput[i])
                    else:
                        tinput.insert(left,tinput[i])
                tinput.pop(i+1)
    return tinput
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值