排序算法详解-- 冒泡排序-选择排序-插入排序-快速排序-归并排序

1. 冒泡排序:时间复杂度:O(n^2) , 空间复杂度:O(1)
第一个逐次和后面比,先拍好后边的,最大/最小。
每次拍好之后减少比较次数,后面排好的不用再去比较

nums = [1, 9, 10, 20, 2 ,5 ,9,0]
① 用 1 分别和列表中的每位元素比较,比1大的话就不动[1, 9, 10, 20, 2 ,5 ,9,0]
② 用 9 去分别比较,10比9 大不动[1, 9, 10, 20, 2 ,5 ,9,0]
… 后面大的保持位置
④ 到 20 比2 大换位置[1, 9, 10, 2, 20 ,5 ,9,0]
⑤ 到 20 比5 大换位置[1, 9, 10, 2, 5 ,20 ,9,0]
⑥ 直到[1, 9, 10, 2, 5 , 9, 0, 20]
… n 是已经排好序的,不用每次遍历到尾部

nums = [1, 9, 10, 20, 2 ,5 ,9]
n = 0
while n < len( nums ):
    for i in range( 0, len( nums ) - 1  - n): # n是后面排好的个数就不循环了
        if nums[i] < nums[i+1]: # 下一个比上一个大就交换位置
            nums[i], nums[i+1] = nums[i+1], nums[i]
    n += 1
print(nums)

2. 选择排序: O(n^2) , 空间复杂度:O(1)
先排好前面,每次选取最小/最大的放到前面,再从未排序中找最小/最大加到排好的后边。

nums = [1, 9, 10, 20, 2 ,5 ,9,0]
① 用 1 分别和列表中的每位元素比较,比1小的话就交换位置[0, 9, 10, 20, 2 ,5 ,9,1]
② 用 9 去分别比较,比2 大换位置[0, 2, 10, 20, 9 ,5 ,9,0]
然后还会继续往下遍历 2 和 5, 9 ,0比,1<2 换位置[0, 1, 10, 20, 9 ,5 ,9,2]
… n 是已经排好序的,不用每次从头开始去遍历,知道最后一位就停止循环

n = 0
while n < len( nums ):
    for i in range( n, len( nums ) - 1 ): # n 开始前面是已经排好的,n是没排好的
        if nums[n] > nums[i+1]: # 如果有比自己还小的换值直到自己最小
            nums[n], nums[i+1] = nums[i+1], nums[n]
    n += 1
print(nums)  -- [0, 1, 2, 5, 9, 9, 10, 20]

细讲网址:https://xiaoqi.blog.csdn.net/article/details/109193651

3. 插入排序:时间复杂度为O(n^2),空间复杂度为O(1)
a = [1, 9, 10, 20, 2 ,5 ,9], 用后面的和前面的比较
① 用 9 和1比,9>1不变[1, 9, 10, 20, 2 ,5 ,9]
② 用 10 和9比 10 >9 不变[1, 9, 10, 20, 2 ,5 ,9]
… 升序的话后者小就不变
③ 用 20 和2比 20 >2 交换位置[1, 9, 10, 2, 20 ,5 ,9]
④ 2 需要和前面排序好的每一个比较 ,比前面小的换位置,小的在前面
[1, 9, 2, 10, 20 ,5 ,9] - [1, 2, 9, 10, 20 ,5 ,9] 直到 1 < 2 停止
… j 是不断变化的,会每次往前移动一位

a = [1, 9, 10, 20, 2 ,5 ,9,0]
for i in range(1, len(a)):  # 没有 i + 1 的情况下不用len(a)-1,因为长度是8索引只能到7
    res = a[i]  # 第二个数开始
    j = i - 1  # 第i前的一个数
    while j >= 0 and res < a[j]: # 如果还有前一个和前一个>后面的就换位置
        a[j], a[j+1] = a[j+1] , a[j]
        j -= 1 # 再去和前一个做比较
        res = a[j+1]   #因为j上一步减1了所以j+1 回到原位
print(a)

4. 快速排序:时间复杂度为最优O(nlogn),最坏时间复杂度O(n^2)空间复杂度为O(1)
因为每次将序列切分为2部分,如果切割了n次把元素切割完,序列的长度为m,则2^n=m,所以切割的时间复杂度为log(n),在每次切割的时候都会比较所有的元素,需要n次,所以整体的时间复杂度为O(nlog(n))。
如果每次左边都只有一个元素那就是最坏时间复杂度 O(n^2)
快速排序: 以第一位为基准,大于基准的放到右边,小于基准的放到左边
稳定性:不稳定
数组 l = [ 2,10,6,9,5,3,4,7,8,0,]
1. 以第一位为基准,大于基准的放到右边,小于基准的放到左边
2. 以l[0] = 2做完为基准,start是0, end是len(l) - 1, low = start, high = end
在这里插入图片描述
3. 只要low没有等于high就一直循环,
注意的是在递归之前mid没变化 ,直到最后放到中间位置
当中只要l[high] >= mid ,位置本就在右边是正确的,不动high+1。
当中只要 l[low] < mid,位置本就在左边是正确的,不动low-1。
每次循环l[low] = l[high], l[high] = l[low]
等于mid的数可以放在左边也可以放在右边,所以只有一个 = 号
在这里插入图片描述

4. high 没变 = len(l) - 1 , low + 1 = 1 循环第三步;

在这里插入图片描述
在这里插入图片描述

def kuaipai(l, start, end):
    low = start
    high = end
    if high <= 1 or low > high:
        return
    mid = l[low]  # 把第一个数作为基准
    # 当low等于high的时候说明已经比较完当前的列表退出
    while high > low:
        while high > low and l[high] >= mid:  #
            # 右边的数大于基准说明位置正确留在原位不动, 右边的索引减一
            high -= 1

        #  high < mid 说明需要放到左边去
        l[low] = l[high]
        while high > low and l[low] < mid:  #
            # 左边的数小于基准说明位置正确留在原位不动, 左边的索引加一
            low += 1

            #  low > mid 说明需要放到左边去
        l[high] = l[low]

    # l[low] = l[high],  l[high] = l[low] 会有两个一样的值,所以让l[low] = mid,并不会丢失数据
    l[low] = mid
    kuaipai(l, start, low - 1)  # 分好左右之后先排左边
    kuaipai(l, low + 1, end) # 排右边
    
if __name__ == '__main__':
    l = []
    import random
    for i in range(0,11):
        l.append( random.randint(1,29) )
    kuaipai(l, 0 , len(l) - 1)
    print(l)

5. 归并排序:时间复杂度为最优最坏都是O(nlogn)
把列表每次2分,知道只有一个元素,把这些元素按照大小逐渐合并成完整列表
在这里插入图片描述
详解看递归分析
在这里插入图片描述

def merge_sort(alist):
    n=len(alist)
    if n<2:
        return alist
    mid = n // 2
    left_li = merge_sort(alist[0:mid])
    right_li = merge_sort(alist[mid:])
    
    # 逐步合并
    result = []
    left_pointer, right_pointer = 0,0
    while left_pointer < len(left_li) and right_pointer <len(right_li):
        if left_li[left_pointer] < right_li[right_pointer]:
            result.append(left_li[left_pointer])
            left_pointer += 1
        else:
            result.append(right_li[right_pointer])
            right_pointer += 1

    # 循环结束之后有某个列表中比较大的是剩下的加到result
    result += left_li[left_pointer:]
    result += right_li[right_pointer:]
    return result

if __name__ == '__main__':
    l = [8,4,5,7,1,3,6,2 ]
    print(merge_sort(l))
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值