DC's blog DC's blog
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)

DC

愿我一生欢喜,不为世俗所及.
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)
  • 计算机基础

  • linux基础

  • mysql

  • git

  • 数据结构与算法

    • 递归_查找
    • LowB三人组
      • 排序
      • 冒泡排序
      • 选择排序
        • 残缺版
        • 完美版
      • 插入排序
    • NB三人组
    • 其它排序
    • 查找习题
  • axure

  • english

  • docker

  • IT_Need
  • 数据结构与算法
DC
2023-02-16
目录

LowB三人组

# 排序

排序: 将一组"无序"的记录序列调整为"有序"的记录序列.
列表排序: 将无序列表变为有序列表.
     输入 - 列表
     输出 - 有序列表
升序和降序
内置排序函数: sort()

常见的排序算法:
     冒泡排序 、 选择排序 、插入排序 ; 快速排序 、 堆排序 、 归并排序 ; 希尔排序 、 计数排序 、桶排序、 基数排序

lowB三人组的时间复杂度都为O(n^2),且都是原地排序.


# 冒泡排序

冒泡排序 (Bubble Sort)
     列表每两个相邻的数, 如果前面比后面大, 则交换这两个数.
     一趟排序完成后, 无序区(没有排好序的)减少一个数, 有序区(已经排好序的)增一个数.
     周而复始, 重复对无序区的冒泡过程..

def bubble_sort(li):
    for i in range(len(li) - 1):
        flag = False
        for j in range(len(li) - i - 1):
            if li[j] > li[j + 1]:  # 大于'>'是升序;小于'<'是降序
                li[j + 1], li[j] = li[j], li[j + 1]
                flag = True
        if not flag:
            return
1
2
3
4
5
6
7
8
9

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

冒泡排序是原地排序, 不需要新的列表, 就在本来的列表上通过交换实现排序. 所谓的冒泡就是浮到顶端.

"""
假如列表有10个数,按理说需要冒泡10趟,但当无序区只有一个数时,就不用冒泡啦.So,共需要冒泡9趟.
range()函数从0开始,顾头不顾尾.. 从第0趟开始..到第8趟,共9趟. 
所以要冒泡多少趟,等同于range(len(li)-1)

假如列表共10个数
第i趟   无序区数据数目len(li)-i  指针位置    是否交换会判断len(li)-i-1
0       10                    0..-..8 -> range(9) 代表会判断9次
1       9                     0..-..7 -> range(8)
...     ...                   ...
7       3                     0..-..1 -> range(2)
...     ...                   ...
8       2                     0       -> range(1)

★ 若一趟冒泡里没有发生任何交换,就可以该列表已经排好序啦!! -- 加一个标志位flag
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

代码实现

import random


def bubble_sort(li):
    for i in range(len(li) - 1):  # 第i趟.
        flag = False
        # 第i趟需要判断交换多少次
        for j in range(len(li) - i - 1):  # j是指针位置
            if li[j] > li[j + 1]:  # 判断交换 大于'>'是升序;小于'<'是降序
                li[j + 1], li[j] = li[j], li[j + 1]
                flag = True
        if not flag:
            return


li = [random.randint(0, 10) for i in range(10)]
print(li)       # [3, 9, 10, 6, 9, 8, 3, 2, 5, 3]
bubble_sort(li)
print(li)       # [2, 3, 3, 3, 5, 6, 8, 9, 9, 10]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 选择排序

选择排序 (select sort)
     一趟排序记录最小的数, 放到第一个位置/无序区第一个位置;
    再一趟排序记录列表无序区最小的数, 放到第二个位置/无序区第一个位置 ... 以此类推.
算法实现关键点: 无序区的范围、无序区最小数的位置.

def sort_simple(li):
    for i in range(len(li) - 1):
        min_loc = i 
        for j in range(i, len(li)):
            if li[j] < li[min_loc]:  # 小于是升序;若是大于,则为降序
                min_loc = j
        li[i], li[min_loc] = li[min_loc], li[i]
    return li
1
2
3
4
5
6
7
8

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

# 残缺版

时间复杂度 O(n^2); 用了两列表,浪费内存..

import random


def select_sort_simple(li):
    li_new = []
    for _ in range(len(li)):  # 0(n)
        min_val = min(li)  # O(n)
        li_new.append(min_val)
        li.remove(min_val)  # O(n) 遍历,找到第一个符合条件的元素删除,后面的元素往前移
    return li_new
  

li = [random.randint(0, 20) for _ in range(10)]
print(li)
print(select_sort_simple(li))

"""
[19, 1, 14, 17, 3, 9, 17, 7, 5, 14]
[1, 3, 5, 7, 9, 14, 14, 17, 17, 19]
"""
# 注:不应该在for循环中修改被迭代的对象..
# for val in li:li.remove(val) -> 遍历li,val的值是li[0]、li[1]..这样来的.li在发生变化.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 完美版

不想开辟新的列表,但想把从无序区选出来最小的数放到某个地方.. 某个地方? 与无序区的 第一个位置/最后一个位置 进行交换.
这里我们以 放到无序区第一个位置 为例.

无序区的范围 -> 第0趟 0到最后;第1趟 1到最后;...;第i趟 i到最后.

import random


def sort_simple(li):
    for i in range(len(li) - 1):  # 与冒泡一样,第i趟
        min_loc = i  # 初始化 将无序区的第0个位置/最左边的位置 设置为无序区最小元素的位置
        # 该for循环完毕后,min_loc就是无序区最小的那个元素的下标
        # 优化:可以range(i+1, len(li)) 偷了一次懒.
        for j in range(i, len(li)):  # 遍历无序区,j是无序区元素的下标
            if li[j] < li[min_loc]:  # 小于是升序;若是大于,则为降序
                min_loc = j
        # 将无序区最小的那个元素与无序区最左边的元素进行交换
        li[i], li[min_loc] = li[min_loc], li[i]
    return li


li = [random.randint(0, 20) for _ in range(10)]
print(li)
print(sort_simple(li))


"""
[5, 5, 11, 8, 6, 0, 9, 3, 18, 6]
[0, 3, 5, 5, 6, 6, 8, 9, 11, 18]
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 插入排序

类似于打牌.
初始的时, 手里(有序区)只有一张牌 ; 每次(从无序区)摸一张牌,插入到手里已有牌的正确位置.

简单来说,就是:
     比较后,若符合条件,会依次将有序区里的排往后挪动,直到条件不成立,此时将摸到的牌插入有序区挪动后空出的那个位置.

def insert_sort(li):
    for i in range(1, len(li)): 
        j = i - 1 
        temp = li[i]
        while j >= 0 and li[j] > temp:  # li[j] > temp大于升序;若是小于,降序
            li[j + 1] = li[j]
            j -= 1
        li[j + 1] = temp
    return li
  
# while循环可改成for循环??是可以的.可以借鉴后面桶排序那,保持每个桶是有序的,用的就是插入.
1
2
3
4
5
6
7
8
9
10
11

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

"""
注:j下标位置的牌必定是手里的牌.

4 5 7 6 --> 一般情况
4 5 7 是手里的牌 ; 6 是摸到的牌
j = 2
   7 < 6 , 7往右移动一个位置,直接覆盖掉6位置的数,摸到的牌会提前存储起来
   现在就是 4 5 "空" 7
j = j -1 = 1
   5 < 6 , 5原地不动..
   6 这张摸到的牌 插入到 "空" 的位置, 即 j+1 的位置, 插入成功.
   

4 5 6 7 3 --> 极端情况
4 5 6 7 是手里的牌 ; 3 是摸到的牌
同理,7 6 5 4 都比3大, 会依次往右移动一个位置.
现在就是 "空" 4 5 6 7, 此时 j = -1
3 这张摸到的牌 插入到 "空" 的位置, 即 j+1=-1+1=0 的位置, 插入成功.
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

代码实现

import random


def insert_sort(li):
    # 从下标1开始,是因为初始的时候,手里有一张下标为0的牌
    for i in range(1, len(li)):  # i表示摸到的牌的下标
        j = i - 1  # j指的是手里的最后一张牌的下标
        # 实现升序排,若手中的牌要比摸到的牌大,手中的牌要往后挪,会覆盖掉摸到的牌,所以需要将摸到的牌的值存储起来
        temp = li[i]
        # while循环找插入的位置
        while j >= 0 and li[j] > temp:  # 大于升序;若是小于,降序
            # while循环开始时 li[j+1] 表明摸到牌; li[j] 表明手里最后一张牌
            # 若手里最后一张牌li[j]大于摸到的牌li[j+1],将手中最后一张牌通过赋值的方式往后移动一个位置
            # 不用担心,摸到的牌的值已经存储起来了
            # 不断比较,极端情况就是:
            #    当j=-1时表明 手中的牌都往 后/右 移动了一个位置
            #    此时,只需要将摸到的牌插入到 第 j+1=-1+1=0 个位置.
            li[j + 1] = li[j]
            j -= 1  # j的箭头往左移动一个位置,便于继续比较手里的牌
        li[j + 1] = temp  # 插入摸到的牌
    return li


li = [random.randint(0, 20) for _ in range(10)]
print(li)               # [0, 14, 18, 19, 10, 6, 7, 15, 16, 17]
print(insert_sort(li))  # [0, 6, 7, 10, 14, 15, 16, 17, 18, 19]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

递归_查找
NB三人组

← 递归_查找 NB三人组→

最近更新
01
deepseek本地部署+知识库
02-17
02
实操-微信小程序
02-14
03
教学-cursor深度探讨
02-13
更多文章>
Theme by Vdoing | Copyright © 2023-2025 DC | One Piece
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式