开始系统学习算法啦!为后面力扣和蓝桥杯的刷题做准备!这个专栏将记录自己学习算法是的笔记,包括概念,算法运行过程,以及代码实现,希望能给大家带来帮助,感兴趣的小伙伴欢迎评论区留言或者私信博主哦!今天更新的是《03_1排序算法:冒泡排序、选择排序、插入排序》
目录
冒泡排序概念
运作过程
算法分析
代码实现
选择排序概念
排序过程
时间复杂度
代码实现
插入排序概念
算法过程
时间复杂度
代码实现
总结
冒泡排序概念
冒泡排序(Bubble Sort)是一种简单的排序算法。它重复的遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。遍历数列的工作室重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小(越大)的元素会慢慢“浮到”数列的顶端。
运作过程
- 比较相邻的元素,如果第一个比第二个大(升序),就交换他们两个。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完之后,最后的元素会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
算法分析
时间复杂度:
- 最优时间复杂度:O(n) 表示遍历一次发现没有任何可以交换的元素,排序结束。)
- 最坏时间复杂度:O(n^2)每一个都要交换。
- 稳定性:稳定
代码实现
def bubble_sort_1(alist):
"""
两个for循环嵌套
以 alist = [1,3,2,5,7,6,4]为例
第一次需要遍历到索引6,第二次5,直到索引0
:param alist:
:return:alist:list
"""
for k in range(0,len(alist)-1):
for i in range(0,len(alist)-1-k):
if alist[i] > alist[i+1]:
alist[i],alist[i+1] = alist[i+1],alist[i] # 实现升序排列
return alist
def bubble_sort_2(alist):
"""
while循环+for循环嵌套
以 alist = [1,3,2,5,7,6,4]为例
主要是k的值的变化
:param alist:
:return:alist:list
"""
k = 0
while k != len(alist)-1:
k += 1
for i in range(0,len(alist)-k):
if alist[i] > alist[i+1]:
alist[i],alist[i+1] = alist[i+1],alist[i] # 实现升序排列
return alist
def bubble_sort_3(alist):
"""
while循环+for循环嵌套
以 alist = [1,3,2,5,7,6,4]为例
如果遍历的时候没有发现要交换的,则这个列表已经是一个排好序的,则直接break
:param alist:
:return:alist:list
"""
for k in range(0,len(alist)-1):
count = 0
for i in range(0,len(alist)-1-k):
if alist[i] > alist[i+1]:
count += 1
alist[i],alist[i+1] = alist[i+1],alist[i] # 实现升序排列
if count == 0:
break
return alist
在这个优化里面只有当遍历完之后发现所有的都不需要操作的时候才会break,所以它的最乐观的时间复杂度还是O(n),最差的时间复杂度还是O(n^2),只在特定的情况下才会有优化的效果。我也尝试着用time模块的time.time()函数来获取程序运行的时间 ,但是程序运行的时间太短了,最终都显示0.0,我也懒得去增大列表的长度了(狗头)。
选择排序概念
选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理如下:
- 首先在未排序序列中找到最小(大)元素,存放在排序序列的起始位置,即第一个位置。
- 然后再将剩余未排序元素中继续寻找最小(最大)元素,放在第二个位置。
- 以此类推,直到所有元素均排序完毕。
总结:先找出最大(最小)的元素,放在第一位或者最后一位。以找出最大的放在第一位为例,先找出最大的放在第一位,再在剩下的元素找出最大的元素,放在第二位,依次进行,直到遍历到最后一个元素,排序结束。选择选的就是最大或者最小的的,相当于挑高个,挑完最高的,再挑次高的,直到结束。
排序过程
时间复杂度
最优时间复杂度:O(n^2)
最坏时间复杂度:O(n^2)
稳定性:不稳定(考虑升序每次选择最大的情况)
代码实现
def selection_sort(alist):
"""
:param alist:
:return: alist
思想就是不断找出最小的放在最前面
以alist = [10,1,3,2,5,7,6,4]为例,n=8
第一次是把1放在最前面
"""
n = len(alist) # 8
for i in range(n): # 0-7
# 下面一段代码是为了找到最小值
min_index = i
for j in range(i,n): #0-7
if alist[min_index] > alist[j]:
min_index = j
# 下面一段代码是为了交换最小值
if min_index != i:
alist[i],alist[min_index] = alist[min_index],alist[i]
return alist
程序可以看成两段,一段是找到剩下里面最小的元素,一段是交换最小值,这两步就可以完成排序,时间复杂度为O(n^2),注意写代码的时候,这两段要分开写,思路更加清晰一些,注意索引的值,可以代入最小时和最大时去检验,这样可以有效避免索引出错。
插入排序概念
插入排序(Insertion Sort)是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应的位置并插入。插入排序在实现上,在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
算法过程
时间复杂度
- 最优时间复杂度:O(n) (升序排列,序列已经处于升序状态)
- 最坏时间复杂度:O(n^2)
- 稳定性:稳定
代码实现
def insert_sort(alist):
"""
:param alist:
:return: alist.sort
插入排序首先需要认定一个基准,一般认为是第一个
以alist = [10,1,3,2,5,7,6,4]为例,首先是1和10比较,需要交换,此时i=0,递减变为-1退出while循环
列表变为alist = [1,10,3,2,5,7,6,4],首先是3和10比较,需要交换,再和1比较,不需要交换,直到i递减到比0小,退出循环
列表的每一个元素都要这么操作,所以外层还要嵌套一个for循环去便利每一个元素
"""
for i in range(1,len(alist)):
while i > 0:
if alist[i-1] > alist[i]:
alist[i-1],alist[i] = alist[i],alist[i-1]
else:
break
i -= 1
return alist
总结
比较一下排序:
从算法实现上来分别比较:
- 冒泡排序是两两比较,分为升序冒泡排序,降序冒泡排序。区别就在于上浮的是大的数还是小的数,其原理都是一样的。冒泡排序的算法实现可以总结成一句话:重复的遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。时间复杂度为O(n^2)
- 选择排序是不断找最大或者最小的元素,将它放在头或者尾,以找出最大的放在第一位为例,先找出最大的放在第一位,再在剩下的元素找出最大的元素,放在第二位,依次进行,直到遍历到最后一个元素,排序结束。选择选的就是最大或者最小的的,相当于挑高个,挑完最高的,再挑次高的,直到结束。
- 插入排序工作原理总结成一句话:通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应的位置并插入。插入排序在实现上,在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。