各种排序算法总结&实现[Python]

主要排序算法:冒泡、选择、插入、希尔、归并、快速、堆排序。时间复杂度和空间复杂度及稳定性(原始序列中相同的两个元素经排序后前后顺序不改变)总结如下图。
各种排序算法总结

1.冒泡排序

从序列第一个数开始,n-1趟遍历,每一趟比较相邻元素,逆序交换,目的在于使得每一趟最后一个元素是最大值。

def bubbleSort(alist):
    for passnum in range(len(alist)-1,0,-1):#排序趟数,从n-1到1
        for i in range(passnum):##每一趟比对相邻数据-逆序交换-比对passnum次
            if alist[i]>alist[i+1]:
                alist[i],alist[i+1]=alist[i+1],alist[i]
    return alist
print(bubbleSort([3,6,8,10,4]))

可加入检测机制改进冒泡法,当检测到某一趟无数据交换发生说明已无逆序数,可结束循环得到有序序列。

def imBubbleSort(alist):
    passnum=len(alist)-1
    exchange=True
    while passnum>0 and exchange:
        exchange=False
        for i in range(passnum):
            if alist[i]>alist[i+1]:
                #exchange=True
                alist[i],alist[i+1]=alist[i+1],alist[i]
                exchange=True#发生交换尚未排序结束
        passnum-=1
    return alist
print(imBubbleSort([3,89,10,45,6,8]))

2.选择排序

遍历序列,n-1趟,每一趟标记最大元素位置,选出最大元素与最后一个元素交换。相比于冒泡法交换次数减少。

def SelectionSore(alist):
    for passnum in range(len(alist)-1,0,-1):#趟数:n-1到1
        maxpos=0
        for i in range(1,passnum+1):#每一趟找最大值位置
            if alist[i]>alist[maxpos]:
                maxpos=i
        alist[maxpos],alist[passnum]=alist[passnum],alist[maxpos]#交换,使最大值在每一趟末尾位置
    return alist
#print(SelectionSore([1,9,30,78,3]))

3.插入排序

类似于整理扑克牌,从第二个元素开始,一次处理一个元素,将该元素与已已排序列比较并寻找插入位置(若当前元素小于已排序中元素i,则i开始整体后移,腾出一个空位给当前元素)。共需要处理n-1(2~末尾)个元素。

def InsertSort(alist):
   for i in range(1,len(alist)):
       newdata=alist[i]#每一项数据进行比对插入
       pos=i
       while pos>0 and alist[pos-1]>newdata:#比对,依次后移比当前项大的数据,空出位置
           alist[pos]=alist[pos-1]
           pos-=1
       alist[pos]=newdata#插入当前项
   return alist
print(InsertSort([1,78,34,10,96]))

4.希尔排序

对于插入排序而言,原始序列越短或列表越接近有序,插入比对次数越少,插入排序越高效。希尔排序在插入排序的基础上改进,将无序表进行间隔划分(逻辑划分,可理解为等间隔采样)形成子列表,再对子列表进行插入排序,这样做的目的是构造短的和接近有序的子列表以提升插入排序效率。间隔从n/2开始依次减半,直到为1。

def gapInsertSort(alist,start,gap):
    for i in range(start+gap,len(alist)):#间隔划分子列表插入排序
        newdata=alist[i]
        pos=i
        while pos>=gap and alist[pos-gap]>newdata:#间隔为gap
            alist[pos]=alist[pos-gap]#移动
            pos-=gap
        alist[pos]=newdata#插入
    return alist
def ShellSort(alist):
    gap=len(alist)//2#初始gap选择一半长
    while gap>0:
        for start in range(gap):
            gapInsertSort(alist,start,gap)
            #print(gap,alist)
        gap=gap//2
    return alist
print(ShellSort([1,56,79,90,3,59,78,33,45,66,99]))

5.归并排序

分治思想,讲原始序列分为一个个子序列,对子序列进行排序合并,直到整个序列有序。
有递归和迭代两种方法。

def recMergeSort(alist):
    #对半分裂o(log n)
    if len(alist)<=1:
        return alist
    else:
        mid=len(alist)//2
        left=recMergeSort(alist[:mid])
        #print('left:',left)
        right=recMergeSort(alist[mid:])
        #print('right:',right)
    #合并过程-O(n)
    merged=[]
    while left and right:
        if left[0]<right[0]:#小的先添加到结果
            merged.append(left.pop(0))
        else:
            merged.append(right.pop(0))
        #print(merged)
    merged.extend(left if left else right)#左半部分或右半部分有剩余
    #print('final:',merged)
    return merged
#print(MergeSort([1,56,78,90,3,4,55]))
def iterMergeSort(alist):
    n=len(alist)
    i=1
    while i<n:
        left_start=left_end=right_start=right_end=0#初始化游标
        while left_start<=n-i:
           merged=[]
           right_start=left_end=left_start+i
           right_end=left_end+i
           if right_end>n:
               right_end=n
           left=alist[left_start:left_end]#会需要额外空间开销,可以不要left和right,直接在原列表切片
           right=alist[right_start:right_end]
           while left and right:
                if left[0]<right[0]:#小的先添加到结果
                    merged.append(left.pop(0))
                else:
                    merged.append(right.pop(0))
                #print(merged)
           merged.extend(left if left else right)#剩余元素添加
           alist[left_start:right_end]=merged##中间排序结果返回给alist-类似于return的作用
           #print(alist,left_start)
           left_start+=i*2##右移游标,依次处理剩余元素
        i*=2##进入下一次merge
    return alist
print(iterMergeSort([5,3,2,7,9,0,77,90,45,44]))

6.快速排序

(1)选择原始序列中任意元素(一般为头、尾或中间)作为基值。
(2)一趟排序:将所有小于基值的元素移动到左边,左右大于基值的元素移动到右边,基值放中间。
(3)重复(2)直到所有元素都排好

def myQuickSort(alist,start,end):
    if start>end:
        return
    else:
        mid=alist[start]
        left=start+1
        right=end
        done=False
        while not done:
            while left<=right and alist[left]<=mid:#取等是因为列表可能包含相等元素
                left+=1
            while right>=left and alist[right]>=mid:
                right-=1
            if left>right:
                done=True
            else:
                alist[left],alist[right]=alist[right],alist[left]
        alist[start],alist[right]=alist[right],alist[start]#右标所指与中值交换,使左边都是小于中值的值,右边都是大于的
        myQuickSort(alist,start,right-1)
        myQuickSort(alist,right+1,end)
        return alist
print(myQuickSort([1,3,9,8,22,43,9,3],0,7))

7.堆排序

应用二叉堆(满足堆次序的完全二叉树)实现排序。时间复杂度o(nlogn),不稳定。

#思路:建立大顶堆-堆顶与最后一个元素(最小值)交换减小规模形成不包含最后一个元素的子堆-堆调整函数实现子堆调整成大顶堆-重复直到堆规模为1。

def heapSort(ilst):
    def heapAdjust(alst,parent_index,length):#堆调整函数
        child_index=parent_index*2+1#左子节点,有一个偏移量因为下标从0开始
        cur_node=alst[parent_index]#当前节点设置为当前父节点

        while child_index<length:#遍历
            if child_index+1<length and alst[child_index]<alst[child_index+1]:#并非叶子节点(最后一个元素)且左子节点小于右子节点-符合大顶堆规则
                child_index+=1#子节点设置为大的那个的下标
            if cur_node>alst[child_index]:#符合大顶堆,不做调整
                break
            alst[parent_index]=alst[child_index]#不符合,父节点与子节点交换,此时的child_index是左右子节点中较大的那个
            parent_index=child_index
            child_index=child_index*2+1
            alst[parent_index]=cur_node
    if ilst==[]:
        return
    rlst=ilst#结果列表赋初值
    length=len(ilst)
    #创建大顶堆
    for i in range(0,length//2)[::-1]:#等于for i in range(length//2-1,-1,-1) 从中间处依次递减直至0位置
        heapAdjust(rlst,i,length)
    #交换堆顶和子堆最后一个叶节点并调整子堆成大顶堆
    for j in range(1,length)[::-1]:#等于 for j in range(length-1,0,-1) 从最末依次递减至1位置
        rlst[j],rlst[0]=rlst[0],rlst[j]#交换子堆的最后一个元素和堆顶
        heapAdjust(rlst,0,j)#调整子堆成大顶堆
    return rlst
ilst=[9,3,4,2,89,10,87]
#print(ilst)
print(heapSort(ilst))
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值