排序全总结

两个点:
1、快排的时候,partition最后操作的是前面的sign, res1
2、归并的时候,如果只是if left < right,肯定是不行的,因为mid = (elft+right)//2,这样的话会导致肯定无法结束,当只有两个数的时候,所以必须if left < right-1。 如果只是用left < right的话,要注意两个的情况,当然也可以解决~~保证两个的时候,可以分成1和1的形式。

https://leetcode-cn.com/problems/sort-an-array/submissions/

面试无非:快排、归并、堆、冒泡、插入,以及复杂度、稳定性

在这里插入图片描述
空间复杂度常规计算:如果新增的内存空间例如列表M在递归中,那么空间就是O(N*M);如果在外部,那么就是O(N+M)。

快排 == 不稳定

相当于先序遍历 时间复杂度O(nlogn),最差O(n*n), 空间复杂度O(logn)===不稳定
空间复杂度的计算取决于递归深度,如果是排序好的数组,递归深度是N,那么空间复杂度就是(N),如果是其他数组,那么递归深度就是log(N)。

def partition(nums, left, right):
    tar = nums[right]
    res1 = left
    res2 = left - 1
    for i in range(left, right):
        if nums[i] <= tar:
            res2 += 1
            nums[res2], nums[res1] = nums[res1], nums[res2]
        res1 += 1
    res2 += 1
    nums[res2], nums[right] = nums[right], nums[res2]
    return res2

def quick_sort(nums, left, right):
    if left < right:
        num = partition(nums, left, right)
        quick_sort(nums, left, num-1)
        quick_sort(nums, num+1, right)
    return nums

nums = [100,2,2,4,6,7,4,2,5,7,8]
# print(quick_sort(nums, 0, len(nums)-1))

归并 == 稳定

等于后续遍历;时间复杂度O(nlogn), 空间O(N), 因为merge阶段使用了空间~~跟上面区别好。
注意点是核心思想是分治法,先分后合;所以并不是类似上面的排除掉一个,而是分成两部分,直到分的只剩一个。注意right~

# 归并排序
def merge(nums, left, mid, right):
    res1 = nums[left:mid]
    res2 = nums[mid:right]
    num1 = 0
    num2 = 0
    tmp = left
    while num1 < len(res1) and num2 < len(res2):
        if res1[num1] <= res2[num2]:
            nums[tmp] = res1[num1]
            num1 += 1
        else:
            nums[tmp] = res2[num2]
            num2 += 1
        tmp += 1
    if num1 == len(res1):
        for i in range(num2, len(res2)):
            nums[tmp] = res2[i]
            tmp += 1
    elif num2 == len(res2):
        for i in range(num1, len(res1)):
            nums[tmp] = res1[i]
            tmp += 1

def merge_sort(nums, left, right):
    if left < right - 1:  # 关键 取还是不取
        mid = (left + right)//2
        merge_sort(nums, left, mid)
        merge_sort(nums, mid, right)
        merge(nums, left, mid, right)
    return nums
class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:

        def merge(nums, left, mid, right):
            res1 = nums[left:mid+1]
            res2 = nums[mid+1:right+1]
            num1 = 0
            num2 = 0
            res = left
            while num1 < len(res1) and num2 < len(res2):
                if res1[num1] < res2[num2]:
                    nums[res] = res1[num1]
                    num1 += 1
                else:
                    nums[res] = res2[num2]
                    num2 += 1
                res += 1
            if num1 == len(res1):
                for i in range(num2, len(res2)):
                    nums[res] = res2[i]
                    res += 1
            else:
                for i in range(num1, len(res1)):
                    nums[res] = res1[i]
                    res += 1

        def merge_sort(nums, left, right):
            if left < right:   ############# right-1  不然的话,用于都有 left=len-1, right=len
                mid = (left + right) // 2
                merge_sort(nums, left, mid)
                merge_sort(nums, mid+1, right)
                merge(nums, left, mid, right)
        merge_sort(nums, 0, len(nums)-1)
        return nums

堆排序 == 不稳定

时间复杂度O(nlogn),空间O(1)。
写的时候犯了三个错误:
1、heapify出错,判断条件要分开,因为不一定时满二叉树
2、注意好是求 最大堆还是最小堆 == 如果是从小到大排序的话,那么求得就是最大堆了~
3、建堆的时候要从左下角,也就是len(nums)//2开始往回~~ 其实len(nums)//2就是左下角了。

# 堆排序
# 建堆
# heapify
# 插入
# heap_sort
def heapify(nums, i, length):
    left = 2 * i + 1
    right = 2 * i + 2
    # if left < length and right < length:  # 错误点三:要分别进行的
    #     res = min(nums[i], nums[left])   # 错误点2,找的是最大的
    #     res = min(res, nums[right])
    #     if res == nums[right]:
    #         nums[right], nums[i] = nums[i], nums[right]
    #         heapify(nums, right, length)
    #     elif res == nums[left]:
    #         nums[left], nums[i] = nums[i], nums[left]
    #         heapify(nums, left, length)
    res = i
    if left < length and nums[i] > nums[left]:
        res = left
    if right < length and nums[res] > nums[right]:
        res = right
    if res != i:
        nums[res], nums[i] = nums[i], nums[res]
        heapify(nums, res, length)

def build_heap(nums):
    for i in range(len(nums)//2, -1, -1):  # 错误1 应该从左下角开始~~不然的话,首位其实不一定是最小的。 nums = [8,5,4,1,3,2,6]
        heapify(nums, i, len(nums))
    return nums

def heap_sort(nums):
    length = len(nums)
    build_heap(nums)
    for i in range(len(nums) - 1, 0, -1):
        nums[0], nums[i] = nums[i], nums[0]
        length -= 1
        heapify(nums, 0, length)
    return nums

print(heap_sort(nums))

冒泡 == 稳定

时间复杂度O(n*n), 空间O(1), 每次搞定最后一位,也就是最大的。

nums = [100,2,2,4,6,7,4,2,5,7,8]
# 冒泡排序
def bubble(nums):
    num = 0
    for i in range(len(nums)):
        res = 0
        for j in range(1, len(nums)-num):
            if nums[j] < nums[res]:
                nums[j], nums[res] = nums[res], nums[j]
            res = j  # 每次都是必须交换序号的
        num += 1
    return nums
print(bubble(nums))

插入排序 == 稳定

时间复杂度O(n*n), 空间O(1), 从左边开始,然后其实前面的部分就都是排好的,只需要插入。

nums = [100,2,2,4,6,7,4,2,5,7,8]
# 插入排序
def insert_sort(nums):
    # 认为前面的都是排好的
    for i in range(len(nums)):
        res = i
        for j in range(i-1, -1, -1): # 因为是从左边开始的,确实左边都是排好的。所以如果遇到比自己小的,就可以break。
            if nums[res] < nums[j]:
                nums[res], nums[j] = nums[j], nums[res]
                res = j
            else:
                break
    return nums
print(insert_sort(nums))

桶排序

数要相对均匀分布,桶的个数也要合理设计。总之桶排序是一种用空间换取时间的排序。在设计桶排序,你需要知道输入数据的上界和下界,看看数据的分布情况,再考虑是否用桶排序
时间复杂度分析
桶排序的时间复杂度到底是多少?
我们假设有n个待排序数字。分到m个桶中,如果分配均匀这样平均每个桶有n/m个元素。首先在这里我郑重说明一下桶排序的算法时间复杂度有两部分组成:
1.遍历处理每个元素,O(n)级别的普通遍历
2.每个桶内再次排序的时间复杂度总和

在这里如果到达极限情况n=m时。就能确保避免桶内排序,将数值放到桶中不需要再排序达到O(n)的排序效果,当然这种情况属于计数排序
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

import random
## 快排
class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        def partition(nums, left, right):
            ## 必须加优化
            res = random.randint(left, right)
            nums[res], nums[right] = nums[right], nums[res]
            res1 = left - 1
            res2 = left - 1
            tmp = nums[right]
            for i in range(left, right):
                if nums[i] <= tmp:
                    res1 += 1
                    res2 += 1
                    nums[res1], nums[res2] = nums[res2], nums[res1]
                else:
                    res2 += 1
            res1 += 1 ## 这里是res1,其实就是原理遗漏了~~
            nums[res1], nums[right] = nums[right], nums[res1]
            return res1
        def quick_sort(nums, left, right):
            if left < right:
                res = partition(nums, left, right)
                quick_sort(nums, left, res-1)
                quick_sort(nums, res+1, right)
        quick_sort(nums, 0, len(nums)-1)
        return nums


## 归并 时间复杂度:O(NlogN),这里 NN 是数组的长度;
# 空间复杂度:O(N)O(N),辅助数组与输入数组规模相当。
import random
class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:

        def merge(nums, left, mid, right):
            res1 = nums[left:mid+1]
            res2 = nums[mid+1:right+1]
            num1 = 0
            num2 = 0
            res = left
            while num1 < len(res1) and num2 < len(res2):
                if res1[num1] < res2[num2]:
                    nums[res] = res1[num1]
                    num1 += 1
                else:
                    nums[res] = res2[num2]
                    num2 += 1
                res += 1
            if num1 == len(res1):
                for i in range(num2, len(res2)):
                    nums[res] = res2[i]
                    res += 1
            else:
                for i in range(num1, len(res1)):
                    nums[res] = res1[i]
                    res += 1

        def merge_sort(nums, left, right):
            if left < right:   ############# right-1  不然的话,用于都有 left=len-1, right=len
                mid = (left + right) // 2
                merge_sort(nums, left, mid)
                merge_sort(nums, mid+1, right)
                merge(nums, left, mid, right)
        merge_sort(nums, 0, len(nums)-1)
        return nums

## 冒泡
class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        def bubble_sort(nums, left, right):
            for i in range(left, right):
                for j in range(left, right-i-1):
                    if nums[j] > nums[j+1]:
                        nums[j], nums[j+1] = nums[j+1], nums[j]
            return nums
        return bubble_sort(nums, 0, len(nums))

## 堆排
class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        def heapify(nums, i, size):
            left = 2*i + 1
            right = 2*i + 2
            res = i
            if left < size and nums[res] < nums[left]:
                res, left = left, res
            if right < size and nums[res] < nums[right]:
                res, right = right, res
            if res != i:
                nums[res], nums[i] = nums[i], nums[res]
                heapify(nums, res, size)
             
        def stack_build(nums):
            for i in range(len(nums)//2, -1, -1):
                heapify(nums, i, len(nums))
        
        def stack_sort(nums):
            stack_build(nums)
            size = len(nums)
            for i in range(len(nums)):
                heapify(nums, 0, size)
                nums[0], nums[size-1] = nums[size-1], nums[0]
                size -= 1
            return nums
        return stack_sort(nums)


## 插入排序
class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        for i in range(1, len(nums)):
            res = i
            for j in range(i-1, -1, -1):
                if nums[res] < nums[j]:
                    nums[j], nums[res] = nums[res], nums[j]
                    res = j
                else:
                    break
        return nums



#思路:每一轮选取未排定的部分中最小的部分交换到未排定部分的最开头,经过若干个步骤,就能排定整个数组。即:先选出最小的,再选出第 2 小的,以此类推。
class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        ## 选择排序
        for i in range(len(nums)):
            res = i
            for j in range(i, len(nums)):
                if nums[res] > nums[j]:
                    res = j
            nums[res], nums[i] = nums[i], nums[res]
        return nums
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值