代码随想录训练营|排序算法总结

目录

总览

比较类排序

交换排序

插入排序

选择排序

归并排序

非比较类排序

计数排序

桶排序

基数排序


总览

十大排序从入门到入赘 | yukiyama (iyukiyama.github.io)https://iyukiyama.github.io/sorting/十大排序算法超全大综合,动图演示,你真的值得拥有! - 力扣(LeetCode)https://leetcode.cn/circle/article/rzsN73/

比较类排序

交换排序

冒泡排序

左右比较,使最值冒出来 稳定

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        # 冒泡排序
        n = len(nums)
        for i in range(n-1,0,-1):
            for j in range(0,i):
                if nums[j+1]<nums[j]:
                    nums[j+1],nums[j] = nums[j],nums[j+1]
        return nums
class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        # 冒泡排序
        n = len(nums)
        end = n-1 # 记录有序区下界
        for i in range(n-1,0,-1):
            is_sweap = False # 记录本轮次是否有交换 可以提前跳出循环
            for j in range(end):
                if nums[j+1]<nums[j]:
                    nums[j+1],nums[j] = nums[j],nums[j+1]
                    is_sweap = True
                    end = j
            if not is_sweap: 
                break
        return nums

快速排序 

选定基准,以基准分区 不稳定 # 7 2 4 4 8 9

递归 

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        # 快速排序
        n = len(nums)
        def quick(left,right):# 左闭右闭
            if right<=0 or left>n or left>=right:return
            mid = left+(right-left)//2
            pivot = nums[mid]
            nums[mid],nums[left] = nums[left],nums[mid]
            slow = left
            for fast in range(left+1,right+1):
                if nums[fast]<=pivot:
                    slow+=1
                    nums[slow],nums[fast] = nums[fast],nums[slow]
            nums[left],nums[slow] = nums[slow],nums[left]
            quick(left,slow-1)
            quick(slow+1,right)
        
        quick(0,n-1)
        return nums

栈 

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        # 快速排序
        n = len(nums)
        stack = []
        stack.append([0,n-1])
        while stack:
            e = stack.pop()
            left = e[0]
            right = e[1]
            if right<=0 or left>n or left>=right:
                continue
            mid = left+(right-left)//2
            pivot = nums[mid]
            nums[mid],nums[left] = nums[left],nums[mid]
            slow = left
            for fast in range(left+1,right+1):
                if nums[fast]<=pivot:
                    slow+=1
                    nums[slow],nums[fast] = nums[fast],nums[slow]
            nums[left],nums[slow] = nums[slow],nums[left]
            stack.append([slow+1,right])
            stack.append([left,slow-1])        
        return nums

插入排序

 简单插入排序

把无序数插入到有序区的对应位置 稳定

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        # 插入排序
        n = len(nums)
        for i in range(1,n):# 指向要进行操作的数
            tmp = nums[i]
            index = i-1
            while index>=0 and nums[index]>tmp: # 插入
                nums[index+1] = nums[index]
                index-=1
            nums[index+1]=tmp
        return nums

 希尔排序

本质上来说,希尔排序也是插入排序,或者说简单插入排序是gap = 1的希尔排序

不稳定 #  {0, 1, 4, 3, 3, 5, 6}

希尔排序的时间复杂度与增量序列的选择有关。最优复杂度增量序列尚未明确。

对于增量,还是用一个数组存储吧 倒推变换太复杂了

 常用增量

 Shell 增量

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        # 插入排序
        n = len(nums)
        gap = n//2 # 步长
        while gap: # 直至步长为0
            for i in range(gap): # 分区
                index = i+gap # 要插入的节点
                while index<n:
                    tmp = nums[index]
                    j = index
                    while j-gap>=0 and tmp<nums[j-gap]: # 插入排序
                        nums[j] = nums[j-gap]
                        j -=gap
                    nums[j] = tmp # 插入的位置
                    index+=gap # 处理下一次节点
            gap//=2
        return nums

 Hibbard增量

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        # 插入排序
        n = len(nums)
        gap = 1 # 步长
        while gap<=n:
            gap *=2
        gap = gap//2-1
        while gap: # 直至步长为0
            for i in range(gap): # 分区
                index = i+gap # 要插入的节点
                while index<n:
                    tmp = nums[index]
                    j = index
                    while j-gap>=0 and tmp<nums[j-gap]: # 插入排序
                        nums[j] = nums[j-gap]
                        j -=gap
                    nums[j] = tmp # 插入的位置
                    index+=gap # 处理下一次节点
            gap =(gap+1)//2-1
        return nums

 Knuth增量

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        # 插入排序
        n = len(nums)
        gap = 1 # 步长
        while gap<=2*n+1:
            gap *=3
        gap = (gap//3-1)//2
        while gap: # 直至步长为0
            print(gap)
            for i in range(gap): # 分区
                index = i+gap # 要插入的节点
                while index<n:
                    tmp = nums[index]
                    j = index
                    while j-gap>=0 and tmp<nums[j-gap]: # 插入排序
                        nums[j] = nums[j-gap]
                        j -=gap
                    nums[j] = tmp # 插入的位置
                    index+=gap # 处理下一次节点
            gap =((gap*2+1)//3-1)//2
        return nums

  Sedgewick增量 

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        # 插入排序
        n = len(nums)
        gap = 1 # 步长
        gaps = []
        k =1
        while gap<n:
            gaps.append(gap)
            gap = 4**k+3*2*(k-1)+1
            k+=1
        while gaps: # 直至步长为0
            gap = gaps.pop()
            for i in range(gap): # 分区
                index = i+gap # 要插入的节点
                while index<n:
                    tmp = nums[index]
                    j = index
                    while j-gap>=0 and tmp<nums[j-gap]: # 插入排序
                        nums[j] = nums[j-gap]
                        j -=gap
                    nums[j] = tmp # 插入的位置
                    index+=gap # 处理下一次节点
        return nums

选择排序

简单选择排序

一轮遍历选最值 置于有序区边界 不稳定 # 7 7 2

import math
class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        # 选择排序
        n = len(nums)
        for i in range(n-1,-1,-1):
            tmp = -math.inf
            index = -1
            for j in range(0,i+1):
                if nums[j]>tmp:
                    tmp = nums[j]
                    index = j
            nums[i],nums[index] = nums[index],nums[i]
        return nums

堆排序

基于数据结构堆(优先队列) 不稳定

建堆:所有非叶子节点逆序下沉

排序:堆顶与有序区下届交换 下沉调整堆

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        # 堆排序
        n = len(nums)
        def down(father,n):# 下沉
            if n<=0:return
            left = 2*father+1
            right = left+1
            while left<n:
                child = left
                if right<n and nums[father]<nums[right] and nums[left]<nums[right]:
                    child = right
                if nums[father]>nums[child]:
                    break
                nums[father],nums[child] = nums[child],nums[father]
                father = child
                left = 2*father+1
                right = left+1
        index = (n-1)//2
        while index>=0:# 建堆
            down(index,n)
            index-=1
        for i in range(n-1,0,-1):# 堆排序
            nums[0],nums[i] = nums[i],nums[0]
            down(0,i)
        return nums

归并排序

分治思想 ,将原待排数组 递归或迭代 地分为左右两半,直到数组长度为 1,然后合并左右数组,在合并中完成排序。

自顶向下:从输入数组出发,不断二分该数组,直到数组长度为1,再执行合并。递归

自底向上 :从输入数组的单个元素出发,一一合并,二二合并,四四合并直到数组有序。迭代

是否原地:是否借助辅助空间

稳定

二路归并排序

自顶向下   非原地

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        # 归并排序 自顶向下 递归
        def combine(a,b): # 左闭右闭
            if b==a:return
            combine(a,(b-a)//2+a)
            combine((b-a)//2+a+1,b)
            nums1 = nums[a:(b-a)//2+a+1]
            nums2 = nums[(b-a)//2+a+1:b+1]
            n = len(nums1)
            m = len(nums2)
            while m or n:
                if m and n:
                    if nums1[n-1]>nums2[m-1]:
                        nums[a+n+m-1] = nums1[n-1]
                        n-=1
                    else:
                        nums[a+n+m-1] = nums2[m-1]
                        m-=1
                elif m:
                    nums[a:a+m] =nums2[0:m]
                    m = 0
                else:
                    n = 0
            return 
        n = len(nums)
        combine(0,n-1)
        return nums

 自底向上 非原地

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        # 归并排序 自底向上 迭代
        gap =1
        l = len(nums)
        while gap<l:
            for j in range(0,l,2*gap):
                left = j
                right = min(j+2*gap-1,l-1)
                nums1 = nums[left:left+gap]
                nums2 = nums[left+gap:right+1]
                n = len(nums1)
                m = len(nums2)
                while n or m:
                    if n and m and nums1[n-1]>nums2[m-1]:
                        nums[left+m+n-1] = nums1[n-1]
                        n-=1
                    elif n and m:
                        nums[left+m+n-1] = nums2[m-1]
                        m-=1
                    elif m:
                        nums[left:left+m] = nums2[0:m]
                        m = 0
                    else:
                        n = 0
            gap*=2
        return nums

自顶向下 原地 

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        # 归并排序 自顶向下 递归
        def combine(a,b): # 左闭右闭
            if b==a:return
            combine(a,(b-a)//2+a)
            combine((b-a)//2+a+1,b)
            left = a # 记数组一起始位置
            right = (b-a)//2+a+1# 数组二起始位置
            while left<right and right<=b:
                while left<=b and nums[left]<=nums[right]: # 找到左边数组第一个大于右边数组首元素的值
                    left+=1
                index = right# 记下right位置
                while right<=b and left<=b and nums[right]<nums[left]:# 找到右边数组第一个大于等于left元素的值
                    right+=1
                # 旋转三次
                re(left,index-1)
                re(index,right-1)
                re(left,right-1)
                # 移动left
                left+=right-index
            return 

        def re(left,right):
            while left<right:
                nums[left],nums[right] = nums[right],nums[left]
                left+=1
                right-=1

        n = len(nums)
        combine(0,n-1)
        return nums

自底向上 原地 

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        def re(left,right):
            while left<right:
                nums[left],nums[right] = nums[right],nums[left]
                left+=1
                right-=1
        # 归并排序 自底向上 迭代
        gap =1
        l = len(nums)
        while gap<l:
            for j in range(0,l,2*gap):
                left = j # 记数组一起始位置
                b = min(j+2*gap-1,l-1) # 数组二终止位置
                right = left+gap # 数组二起始位置
                while left<right and right<=b:
                    while left<=b and nums[left]<=nums[right]: # 找到左边数组第一个大于右边数组首元素的值
                        left+=1
                    index = right# 记下right位置
                    while right<=b and left<=b and nums[right]<nums[left]:# 找到右边数组第一个大于等于left元素的值
                        right+=1
                    # 旋转三次
                    re(left,index-1)
                    re(index,right-1)
                    re(left,right-1)
                    # 移动left
                    left+=right-index
            gap*=2
        return nums

 多路归并

非比较类排序

计数排序

核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。

不稳定 优化后可稳定

优化前不稳定 

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        # 计数排序
        n = len(nums)
        end = max(nums)
        start = min(nums)
        tmp = [0]*(end-start+1)
        res = []
        for num in nums:
            tmp[num-start]+=1
        for i in range(end-start+1):
            while tmp[i]:
                res.append(i+start)
                tmp[i]-=1
        return res

优化后稳定 

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        # 计数排序
        n = len(nums)
        end = max(nums)
        start = min(nums)
        tmp = [0]*(end-start+1)
        res = [0]*n
        for num in nums:
            tmp[num-start]+=1
        for i in range(1,end-start+1):# j对应到它的下标
            tmp[i]+=tmp[i-1]
        for i in range(n-1,-1,-1):# 倒序
            res[tmp[nums[i]-start]-1] = nums[i]
            tmp[nums[i]-start]-=1        
        return res

桶排序

计数排序的升级版,利用了函数的映射关系:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。

高效:

  1. 在额外空间充足的情况下,尽量增大桶的数量;
  2. 使用的映射函数能够将输入的 N 个数据均匀的分配到 K 个桶中。
class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        # 桶排序
        n = len(nums)
        buckets = [[]for _ in range(n)]
        min_num = min(nums)
        max_num = max(nums)
        if min_num==max_num:return nums
        for num in nums:
            index = (num-min_num)*(n-1)//(max_num-min_num)
            buckets[index].append(num)
        res = []
        for bucket in buckets:
            bucket.sort()
            res +=bucket
        return res

基数排序

将整数按位数切割成不同的数字,然后按每个位数分别比较。

要求正数 需要预处理 但有可能越界 因此可以将[0,9]扩展到[-9,9]

获得最大值的位数 按每一位对进行基数排序

基数排序要求对每一位的排序 (计数排序或非计数排序) 必须是稳定排序,否则无法得到正确结果。

以计数排序为基础 

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        # 基于计数排序的基数排序
        n = len(nums)
        buckets = [[]for _ in range(n)]
        max_num = max(max(nums),-min(nums)) # 绝对值最大
        width = 0
        while max_num:
            max_num//=10
            width+=1
        k = 0
        while k<width:
            buckets = [0]*20
            for num in nums:
                if num>=0:
                    index = num//10**k%10+10
                    buckets[index]+=1
                else:
                    num = -num
                    index = num//10**k%10
                    buckets[9-index]+=1
            for i in range(1,20):
                buckets[i]+=buckets[i-1]
            tmp = [0]*n
            for i in range(n-1,-1,-1):
                num = nums[i]
                if num>=0:
                    index = num//10**k%10+10
                    tmp[buckets[index]-1] = num
                    buckets[index]-=1
                else:
                    num = -num
                    index = num//10**k%10
                    tmp[buckets[9-index]-1] = -num
                    buckets[9-index]-=1
            nums = tmp
            k+=1
        return nums

 以非计数排序(如桶排序)为基础 

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        # 基于桶排序的基数排序
        n = len(nums)
        buckets = [[]for _ in range(n)]
        max_num = max(max(nums),-min(nums)) # 绝对值最大
        width = 0
        while max_num:
            max_num//=10
            width+=1
        k = 0
        while k<width:
            buckets = [[] for _ in range(20)]
            for num in nums:
                if num>=0:
                    index = num//10**k%10+10
                    buckets[index].append(num)
                else:
                    num = -num
                    index = num//10**k%10
                    buckets[9-index].append(-num)
            nums = []
            for bucket in buckets:
                nums+=bucket
            k+=1
        return nums

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14天的训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15天的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16天的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值