python每日算法 | 图文挑战十大排序算法DAY1,再也不用担心面试官问冒泡、选择、插入排序!持续更新,收藏起来❤

 创作不易,来了的客官点点关注,收藏,订阅一键三连❤😜 


前言

程序=数据结构+算法,算法是数学理论和工程实现的杂糅,是一个十分有趣神奇的学问。搞懂算法用另一种视角看编程,又会是一种全新的感受,如果你也在学习算法,不妨跟主任萌新超差一起学习,拿下算法!


系列文章目录

python每日算法|实现四大查找算法,生动形象,保证一看就会!

python每日算法——算法的起步与递归算法(汉诺塔问题)


概述

本期的内容将介绍十大排序算法之冒泡排序、选择排序以及插入排序,通过本期内容你不仅能知道他们的代码如何用python实现,还将学会用装饰器来查看算法的运行时间等等!再也不用担心面试官问冒泡、选择、插入排序!

目录

前言

系列文章目录

概述

超超python算法学习思维导图

排序

排序是什么

列表排序

常见的排序算法

冒泡排序

什么是冒泡排序

代码讲解

代码优化

选择排序

什么是选择排序

代码讲解

思考:该代码有什么不足之处?或需要改进的地方?

优化后的选择排序代码

插入排序

什么是插入排序?

代码讲解

冒泡排序、选择排序、插入排序小总结

思考:三种算法效率如何体现


超超python算法学习思维导图

思维导图将每日更新,欢迎大家订阅超超的python每日算法专栏 


排序

排序是什么

排序:将一组“无序”的记录序列调整为“有序”的记录序列

列表排序

列表排序:将无序列表变为有序列表

输入:列表

输出:有序列表

顺序的类型:升序(从小到大)与降序(从大到小)

内置排序函数:sort()

常见的排序算法

排序基础三人组:冒泡排序 选择排序 插入排序

排序进阶三人组:快速排序 堆排序 归并排序

其他排序算法:希尔排序 计数排序 基数排序 桶排序

(可能归纳不全,但保证管用)


冒泡排序

什么是冒泡排序

冒泡排序(Bubble Sort)是一种简单直观的排序算法。它重复地走访要排序的数列,依次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成这个算法的名字由来是因为越小的元素会经由交换慢慢""到数列的顶端。

简单来说,列表每两个相邻的数,如果前面的比后面的大则交换这两个数,一趟排序完成后,则无序区减少一个数,有序区增加一个数。(每一趟冒出一个无序区最大的数--->冒泡排序)

 图片来自菜鸟教程

代码讲解

# 冒泡排序初级代码

import random

def bubble_sort(lst):

    for i in range(len(lst) - 1):  # 表示第i趟,此处也可以直接用len(lst),但是直接用len(lst)会多走了最后一遍

        for j in range(len(lst)-i-1):  # 表示箭头(下标)可移动的无序区范围,比如长为10的列表,i取值则是0-9,第二次查找则无序区的长度为10-i(此时是1,第一次是0)-1(-1因为是根据下标查找)=8,因此箭头范围0-8

            if lst[j] > lst[j+1]: # 此时是升序排序,>改为<则改为了降序

                lst[j],lst[j+1] = lst[j+1],lst[j]

        print(f"第{i+1}趟后的列表为:{lst}")  # 查看排序过程

 

lst1 = [random.randint(0,10000) for i in range(5)]

print(f"初始列表:{lst1}")

bubble_sort(lst1)

# 结果

# 初始列表:[3053, 8957, 2153, 4502, 2518]

# 第1趟后的列表为:[3053, 2153, 4502, 2518, 8957]

# 第2趟后的列表为:[2153, 3053, 2518, 4502, 8957]

# 第3趟后的列表为:[2153, 2518, 3053, 4502, 8957]

# 第4趟后的列表为:[2153, 2518, 3053, 4502, 8957]

lst2 = [1,2,3,8,7,6,5]

print(f"初始列表:{lst2}")

bubble_sort(lst2)

# 初始列表:[1, 2, 3, 8, 7, 6, 5]

# 第1趟后的列表为:[1, 2, 3, 7, 6, 5, 8]

# 第2趟后的列表为:[1, 2, 3, 6, 5, 7, 8]

# 第3趟后的列表为:[1, 2, 3, 5, 6, 7, 8]

# 第4趟后的列表为:[1, 2, 3, 5, 6, 7, 8]

# 第5趟后的列表为:[1, 2, 3, 5, 6, 7, 8]

# 第6趟后的列表为:[1, 2, 3, 5, 6, 7, 8]

此时我们发现冒泡排序多走路了一趟,第3趟和第6趟一样,且第3趟已排好,那么如何对代码进行改进?

代码优化

# 改进后的代码

def bubble_sort(lst):

    for i in range(len(lst) - 1):  # 表示第i趟

        exchange = False  # 每一趟做标记

        for j in range(len(lst)-i-1):  # 表示箭头

            if lst[j] > lst[j+1]: # 此时是升序排序,>改为<则改为了降序

                lst[j],lst[j+1] = lst[j+1],lst[j]

                exchange = True  # 进行了交换,exchange标记为Ture

        print(f"第{i+1}趟后的列表为:{lst}")  # 查看排序过程

        if not exchange: # 如果没有进行交换,直接返回,优化的步骤

            return

lst2 = [1,2,3,8,7,6,5]

print("***改进后的冒泡排序***")

print(f"初始列表:{lst2}")

bubble_sort(lst2)

# 结果

# ***改进后的冒泡排序***

# 初始列表:[1, 2, 3, 8, 7, 6, 5]

# 第1趟后的列表为:[1, 2, 3, 7, 6, 5, 8]

# 第2趟后的列表为:[1, 2, 3, 6, 5, 7, 8]

# 第3趟后的列表为:[1, 2, 3, 5, 6, 7, 8]

# 第4趟后的列表为:[1, 2, 3, 5, 6, 7, 8]

冒泡算法的时间复杂度:O(n2),两层查找。


选择排序

什么是选择排序

选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理如下。首先在未排序序列中找到最小(大)元素存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

简单来说,选择排序就是每一趟排序记录最小的数,并放到第一个位置,在一趟排序记录列表中无序区最小的数,放到有序区第二个位置…….以此循环,直到只剩最后一个数时,此数绝对是最大的数。

此算法的关键点时:有序区和无序区以及无序区最小数的位置。

图片来自菜鸟教程 

代码讲解

简单易理解的选择排序

def select_sort_simple(lst):

    new_lst = []

    for i in range(len(lst)):

        min_val = min(lst)

        new_lst.append(min_val)

        lst.remove(min_val)

    return new_lst

 

lst1 = [3,2,4,13,11,8]

result = select_sort_simple(lst1)

print(result)

# 结果

# [2, 3, 4, 8, 11, 13]

思考:该代码有什么不足之处?或需要改进的地方?

1.建立新的列表占用了内存

2.时间复杂度较大,O(n^2)

接下来我们对列表进行优化

优化后的选择排序代码

def select_sort(lst):

    for i in range(len(lst) - 1):  # i代表第几趟

        min_location = i # 最小位置的标记,第一次默认最小的数为无序区的第一个,即下标为i

        for j in range(i+1,len(lst)): # 从i开始相当于自己和自己比了一次,此步骤多余,因此从i+1开始

            if lst[j] < lst[min_location]:

                min_location = j

        lst[i],lst[min_location] = lst[min_location],lst[i] # 最小的值和有序区的最后一个值进行交换

        print(f"第{i + 1}趟后的列表为:{lst}")

 

 

lst1 = [3,2,4,13,11,8]

select_sort(lst1)

# 结果

# 第1趟后的列表为:[2, 3, 4, 13, 11, 8]

# 第2趟后的列表为:[2, 3, 4, 13, 11, 8]

# 第3趟后的列表为:[2, 3, 4, 13, 11, 8]

# 第4趟后的列表为:[2, 3, 4, 8, 11, 13]

# 第5趟后的列表为:[2, 3, 4, 8, 11, 13]

选择排序的时间复杂度:O(n2)(两层循环)


插入排序

什么是插入排序?

先举个生活实例

假设,你的手上有一副排好顺序的牌(有序区),此时你需要从还没摸完的牌(无序区)里摸一张牌,插入到已有牌的手里,直到摸完牌(从无序去),最后手上的牌(有序区)也排好序了。

插入排序(英语:Insertion Sort)的工作原理是通过构建有序序列对于未排序数据在已排序序列中从后向前扫描,找到相应位置并插入。

图片来自菜鸟教程 

代码讲解

def insert_sort(lst):

    for i in range(1,len(lst)):  # i表示摸到的牌的下标

        tmp = lst[i] # tmp代表摸到的牌

        j = i - 1 # j代表的是手里的牌的下标,手上自动已有第一张牌

        while lst[j] > tmp and j >= 0: # 需要移动有序区牌的情况

            lst[j+1] = lst[j]

            j -= 1

        lst[j+1] = tmp  # lst[j+1]是用来存放要插入的牌

        print(f"第{i}趟的列表:{lst}")

 

lst1 = [3,2,5,8,6,9,7]

print(f"原列表{lst1}")

insert_sort(lst1)

# 结果原列表[3, 2, 5, 8, 6, 9, 7]

# 第1趟的列表:[2, 3, 5, 8, 6, 9, 7]

# 第2趟的列表:[2, 3, 5, 8, 6, 9, 7]

# 第3趟的列表:[2, 3, 5, 8, 6, 9, 7]

# 第4趟的列表:[2, 3, 5, 6, 8, 9, 7]

# 第5趟的列表:[2, 3, 5, 6, 8, 9, 7]

# 第6趟的列表:[2, 3, 5, 6, 7, 8, 9]

插入排序时间复杂度:O(n2)


冒泡排序、选择排序、插入排序小总结

1.三种排序方法的时间复杂度都是O(n2)

2.三种算法都属于原地排序,为创建新的列表

3.效率较低

思考:三种算法效率如何体现

现在利用装饰器,以冒泡排序为例子计算一下运算时间

from runtime import *

 

@runtime

def bubble_sort(lst):

    for i in range(len(lst) - 1):  # 表示第i趟

        exchange = False  # 每一趟做标记

        for j in range(len(lst)-i-1):  # 表示箭头

            if lst[j] > lst[j+1]: # 此时是升序排序,>改为<则改为了降序

                lst[j],lst[j+1] = lst[j+1],lst[j]

                exchange = True  # 进行了交换,exchange标记为Ture

        # print(f"第{i+1}趟后的列表为:{lst}")  # 查看排序过程

        if not exchange: # 如果没有进行交换,直接返回,优化的步骤

            return

 

lst = list(range(10000))

random.shuffle(lst)

bubble_sort(lst)

# 结果

# bubble_sort执行用时12.76702880859375s

我们发现当列表长度比较长时,冒泡排序需要的时间很长(相对于机器的运算)

那么是否有时间复杂度更低的排序算法呢?

答案是肯定有的,明天超超来解密!

创作不易,客官点个赞,评论一下吧!一起加油❤😜 

  • 16
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chaochao️

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值