经典排序算法

1、冒泡
时间复杂度O(N^2),空间复杂度O(1),可实现稳定

def bubblesort(arr):
    if not arr or len(arr)<2:
        return arr
    for i in range(len(arr)-1):
        for j in range(len(arr)-i-1):#不会越界
            if arr[j]>arr[j+1]:
                arr[j],arr[j+1]=arr[j+1],arr[j]
    return arr

2、选择
时间复杂度O(N^2),空间复杂度O(1),不可实现稳定

def selectsort(arr):
    if not arr or len(arr)<2:
        return arr
    for i in range(len(arr)-1):
        mindex=i
        for j in range(i+1,len(arr)):
            if arr[mindex]>arr[j]:
                mindex=j
        arr[i],arr[mindex]=arr[mindex],arr[i]
    return arr

3、插入
时间复杂度O(N^2),空间复杂度O(1),可实现稳定

def insertSort(arr):
    if not arr or len(arr)<2:
        return arr
    for i in range(1,len(arr)): #从位置1开始
        for j in range(i-1,-1,-1): # j=i-1为当前位置,试探j+1位置
            if arr[j]>arr[j+1]:
                arr[j],arr[j+1] = arr[j+1],arr[j]
            else:
                # 位置确定为j
                break
    return arr

4、归并:
时间复杂度master公式:O(NlogN),空间复杂度O(N),[help数组]
可以实现稳定

def merge(a,b): #Y排
    i=0
    j=0
    help=[]
    while i<len(a) and j<len(b):
        if a[i]<b[j]:
            help.append(a[i])
            i=i+1
        else:
            help.append(b[j])
            j=j+1
    if i==len(a):   #两个必有一个越界
        for c in b[j:]:
            help.append(c)
    else:
        for c in a[i:]:
            help.append(c)
    return help
    
def merge_sort(arr): #递归过程
    if len(arr)<2:
        return  arr
    mid=len(arr)//2 #注意//,表示整数除法
    left=merge_sort(arr[:mid])
    right=merge_sort(arr[mid:])
    return  merge(left,right)
print(merge_sort([3,4,5,2,4,1]))

归并应用:求小和

def merge_sort(arr, l, r):
    if l == r :
        return 0  #求小和
        #return    #归并排序
    mid = l + ((r - l) >> 1)
    #merge_sort(arr, l, mid)    #归并排序
    #merge_sort(arr, mid + 1, r) #归并排序
    return  merge_sort(arr, l, mid) + merge_sort(arr, mid+ 1 , r)+merge(arr, l, mid, r)# 求小和
    #return merge(arr, l, mid, r)  #归并排序
def merge(arr, l, m, r):
    help = []
    i = l
    j = m + 1
    sum = 0
    while i <= m and j <= r:
        if arr[i] <arr[j] :
            sum += (r - j + 1 ) * arr[i] #产生小和数
            help.append(arr[i])
            i += 1
        else :
            sum +=0
            help.append(arr[j])
            j+= 1
    while i <= m :
        help.append(arr[i])
        i += 1
    while j <= r :
        help.append(arr[j])
        j += 1
    for i in range(len(help)):
        arr[l + i] = help[i]
    #return arr  #递归的返回
    return sum     #小和数返回
arr = [2,4,7,5,2,]
print(merge_sort(arr,0,len(arr)- 1 ))

5、快速排序:
经典:最后一个数划分
随机:随机一个数划分
时间复杂度期望O(NlogN),但常数项优良,工程上常用
最好空间复杂度O(logN),记录划分值, 最差O(N)

不可实现稳定

(1)荷兰国旗问题(小于、等于、大于)
时间复杂度O(N),空间复杂度O(1),partition过程

def helan(arr,l,r):  #对l进行了复用
    less=l-1
    most=r+1
    #most=r    #(1)
    s=arr[r]   #记录划分值
    while (l<most):
        if arr[l]<s:
        #if arr[l]<arr[r]:#(1)
            arr[less + 1], arr[l] = arr[l], arr[less + 1]
            less = less + 1
            l+=1
        elif arr[l]>s:
        #elif arr[l] > arr[r]:#(1)
            arr[most-1],arr[l]=arr[l],arr[most-1]
            most=most-1
        else:l+=1
    #arr[most],arr[r]=arr[r],arr[most] #大于区域最右最左交换,(1)
    return arr,less+1,most-1   #等于区域的左边界和有边界
    #return arr,less+1,most     #(1)
arr=[3,4,5,0,6,4]
print(helan(arr,0,len(arr)-1))

随机快速排序

import random
def helan(arr,l,r):
    less=l-1
    most=r
    while (l<most):
        if arr[l]<arr[r]:
            arr[less + 1], arr[l] = arr[l], arr[less + 1]
            less = less + 1
            l+=1
        elif arr[l]>arr[r]:
            arr[most-1],arr[l]=arr[l],arr[most-1]
            most=most-1
        else:l+=1
    arr[most],arr[r]=arr[r],arr[most]
    return less+1,most  #等于区域的左边界和有边界
def quicksort(arr,l,r):
    if l<r:   #停止条件
        m=random.randint(l,r)
        arr[r],arr[m]=arr[m],arr[r] #随机快速排序,固定数值为划分值则为经典快速排序
        p=helan(arr,l,r)           #荷兰国旗问题,记录断点信息
        quicksort(arr,l,p[0]-1)#排左区
        quicksort(arr,p[1]+1,r)#排右区
    return arr
if __name__=="__main__":
    arr=[7,8,6,4,5]
    print(quicksort(arr,0,len(arr)-1))

6、堆排序
空间复杂度O(1),时间复杂度O(NlogN)

时间复杂度:
建立:log1+log2+log3+…logN=log(123*…*N)=O(N) [数学上可以证明]
交换向下调整:O(NlogN)
不稳定,常数项较大,工程上不常用

**堆结构:**逻辑上是一个完全二叉树【从左位置填,填满再填下一层】
**落地结构:**数组结构

数组对应堆结构:
i
左:2i+1 右:2i+2 父:(i-1)/2

大根堆:每一棵子树的最大值都在头节点
小根堆:每一棵子树的最小值都在头节点

调整大根堆:
遍历每一个数,让他与父节点进行比较,比父节点大则交换位置,交换完当前位置变成父节点位置,继续寻找父节点
堆排序思想:
(1)建立大根堆
(2)第一个数与最后一个交换,调整越界条件,相当于堆减大小
(3)从头节点开始,每一个节点与子节点进行比较,若子节点大,交换位置
(再次建立大根堆)
(4)第一个数与最后一个交换,调整越界条件,相当于堆减大小
(5)重复,直到堆的大小减为零

代码:

def heapinsert(arr,index): #调整成大根堆,可能无序
    while arr[int(index)]>arr[int((index-1)/2)]:
        arr[index],arr[int((index-1)/2)]=arr[int((index-1)/2)],arr[index]
        index=(index-1)/2

def heapfy(arr,index,size): #size为heapsize
    left=index*2+1          #左孩子
    while left<size:        #判断是否越界
        if left+1<size and arr[left+1]>arr[left]: #右孩子不越界且右孩子大于左孩子
            largest=left+1
        else:largest=left   #得到较大孩子的下标
        if arr[largest]<arr[index]:
            largest=index   #得到父节点与子节点大值的下标
        if largest==index:  #没变,不用换,退出
            break
        arr[index],arr[largest]=arr[largest],arr[index]  #子节点大,交换
        index=largest       #继续再往下找子节点
        left=index*2+1
def heapsort(arr):
    if len(arr)<=1:
        return
    for i in range(len(arr)): #遍历每一个位置进行调整,调整成大根堆
        heapinsert(arr,i)

    headsize=len(arr)
    arr[0],arr[len(arr)-1]=arr[len(arr)-1],arr[0] #交换大根堆第一个和最后一个
    headsize-=1                                   #调整越界条件,相当于堆减大小
    while headsize>0:                             #直到堆的大小减为0
        heapfy(arr,0,headsize)                    #又得到大根堆
        arr[0], arr[headsize - 1] = arr[headsize - 1], arr[0]  # 交换大根堆第一个和最后一个
        headsize -= 1
    return arr
if __name__=="__main__":
    arr=[2,6,7,3,4]
    print(heapsort(arr))

堆排序应用:
求容器数的最大值,并弹出
思路:(最大值为位置0的数,弹出:与最后一个数交换,去掉即可)
每次调整时间复杂度O(logN),N为节点个数,logN为高度
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值