时间/空间复杂度、冒泡/选择/插入/快速/归并/计数排序

时间复杂度

  • 时间复杂度是用来估计算法运行时间的一个式子(单位)——执行的次数

  • 一般来说,时间复杂度高的算法比低的算法快

  • 如何一眼判断时间复杂度

    1、循环减半的过程(O(logn))

    2、几次循环就是n的几次方的复杂度(O(nn))

    空间复杂度

    程序执行所耗内存空间的大小

1、冒泡排序

拿第一个数与后一个数比,如果大,就挪到后面;如果后面的数大,就开始用这个大的数再往后走,直到比到最后一个。接着从头拿新的第一个数去重复,直到排完序

def bubble_sort(li):
    for i in range(len(li)):
        for j in range(len(li)-i-1):  # 每次内层循环比外层少一次
            if li[j] > li[j+1]:  # <就是倒序
                li[j], li[j+1] = li[j+1], li[j]
 # 时间复杂度:O(n^2)
 # 空间复杂度:O(1)
    
# 优化
def bubble_sort(li):
    for i in range(len(li)):
        flag=True
        for j in range(len(li)-i-1):  # 每次内层循环比外层少一次
            if li[j] > li[j+1]:
                li[j], li[j+1] = li[j+1], li[j]
                flag = False
        if flag:
            return None

2、选择排序

拿出第一个元素,认为它是最小的,然后与后面的所有元素依次进行比较,如果基准元素比后面的小就不变,否则就交换位置

def select_sort(l):
    for i in range(len(l)):
        min_ele = i  # 把第一个元素的索引定位最小的基准
        for j in range(i+1, len(l)):
            if l[min_ele] > l[j]:
                l[min_ele], l[j] = l[j], l[min_ele]

# 时间复杂度:O(n^2)
# 空间复杂度:O(1)

3、插入排序思路

  • 列表被分为有序区和无序区两部分。最初有序区只有一个元素。
  • 每次从无序区选择一个元素,插入到有序区的位置,直到无序区变空
def insert_sort(li):
    for i in range(1, len(li)):  # 初始从索引1开始,索引0是有序区
        tmp = li[i]  # 第一个元素
        j = i - 1  # 最后一个元素的索引
        while j>=0 and tmp<li[j]:  # tmp小,就把大的往后排
            li[j+1]=li[j]
            j=j-1
        li[j+1]=tmp
# 时间复杂度:O(n^2)
# 空间复杂度:O(1)

4、快速排序

取一个元素p(第一个元素),使元素p归位,意思就是列表被p分为两部分,左边都比p小,右边的都比p大。然后利用递归完成其他部分的排序

  • 排序前:5 7 4 6 3 1 2 9 8
  • p归位: 2 1 4 3 5 6 7 9 8
  • 目标: 1 2 3 4 5 6 7 8 9
def partition(li, left, right):
    tmp = li[left]
    while left < right:
        while left < right and  li[right] >= tmp:
            right = right - 1
        li[left] = li[right]
        while left < right and li[left] <= tmp:
            left = left + 1
        li[right] = li[left]
    li[left] = tmp
    return left

def Quick_Sort(li, left, right):
    if left < right:
        mid = partition(li, left, right)  ### O(n)
        Quick_Sort(li, left, mid-1)   ####  O(logn)
        Quick_Sort(li, mid+1,right)
# 时间复杂度:O(nlogn)

另一种实现

def quick_sort(b):
   """快速排序"""
   if len(b) < 2:
       return b
   # 选取基准,随便选哪个都可以,选中间的便于理解
   mid = b[len(b) // 2]
   # 定义基准值左右两个数列
   left, right = [], []
   # 从原始数组中移除基准值
   b.remove(mid)
   for item in b:
       # 大于基准值放右边
       if item >= mid:
           right.append(item)
       else:
           # 小于基准值放左边
           left.append(item)
   # 使用迭代进行比较
   return quick_sort(left) + [mid] + quick_sort(right)
print(quick_sort(ls))

5、归并排序

分解:先将列表劈开为两部分,然后再将两个子列表分别劈开,直到每个都是单个元素,单个元素一定是有序的

合并:然后递归的合并相邻的拆分项

### 时间复杂度:O(nlogn)
### 空间复杂度:O(n)
#### python 底层 sorted()函数, 采用的排序算法是 TimSorted 包含了归并排序和插入排序
#### TimSorted 的时间复杂度是:O(nlogn)

def merge(li, low, mid, high):
    i = low
    j = mid + 1
    ltmp = []
    while i <= mid and j <=high:
        if li[i] <= li[j]
        	ltmp.append(li[i])
        	i += 1
        else:
            ltmp.append(li[j])
            j += 1
    while i <= mid:
        ltmp.append(li[i])
        i += 1
    while j <= high:
        ltmp.append(li[j])
        j += 1
    li[low:high+1] = ltmp  # 将临时列表赋值给原列表

def merge_sort(li, low, high):
    if low < high:
        mid = (low + high)  // 2
        # 分解
        merge_sort(li, low, mid)
        merge_sort(li, mid+1, high)
        # 合并
        merge(li, low, mid, high)	

6、计数排序

计数排序的原理如下:

​ 1、假如有一个长度为5的列表a:[1, 2, 3, 4, 5]

​ 2、我们先生成一个长度为a列表最大元素+1的临时列表b,其元素都为0:[0, 0, 0, 0, 0, 0]

​ 3、遍历原列表a,将列表a的元素当作列表b的索引,然后:b[a元素] += 1

​ 4、这样得到的b列表就会变成:[0,1,1,1,1,1]

​ 5、将b列表的索引赋值给a列表就完成了排序

def count_sort(li):
    count = [0 for x in range(max(li)+1)]
    
    for i in li:
        count[i] += 1
    li.clear()
    for index, num in enumerate(count):
        # index:索引     num:索引出现的次数
        for x in range(num):  # 防止某些数出现两次及以上
        	li.append(index)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值