冒泡排序:
比较相邻的元素。如果第一个比第二个大(升序),就交换他们两个。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较
时间复杂度:O(n^2)
最优时间复杂度:O(n)
稳定性:稳定
def bubble(li):
n = len(li)
# j 代表 当前无序序列的个数
for j in range(n,1,-1):
# 1 将序列最大数移动到无序序列尾端(遍历比较,前大后小则交换)
count = 0
for i in range(0,j-1):
if li[i]>li[i+1]:
li[i],li[i+1] = li[i+1],li[i]
count += 1
# 若没有发生交换,则算法退出
if count==0:
return
# 2 对剩余无序序列li[0:n-1]重复步骤1
选择排序:
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
时间复杂度:O(n^2)
稳定性:不稳定
def selection(li):
n = len(li)
# j 代表当前有序序列的个数(无序序列的首个元素位置)
for j in range(0,n-1):
# 1 找到最小元素并记录该值索引(遍历比较,小则更新)
index = j
for i in range(j+1,n):
if li[i]<li[index]:
index = i
# 至此,第min_index个元素就是最小元素
# 2 交换最小值和无序序列首个元素
li[index],li[j] = li[j],li[index]
# 3 对剩余无序序列li[1:n]重复步骤1 2
插入排序:
通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
时间复杂度:O(n^2)
最优时间复杂度:O(n)
稳定性:稳定
def insertion(li):
n = len(li)
#j 代表当前有序序列的个数
for j in range(1,n):
# 1 将无序序列首个元素向前插入有序序列(反向遍历,前大后小则交换)
for i in range(j,0,-1):
if li[i]<li[i-1]:
li[i],li[i-1] = li[i-1],li[i]
else:
# 若没有发生前大后小则步骤1结束
break
# 2 对剩余无序序列重复步骤1
希尔排序:
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。
平均时间复杂度O(n^1.3~2)
最优时间复杂度:O(nlogn)
最坏时间复杂度:O(n^2)
def shell(li):
n = len(li)
# 1 确定步长分组(步长=长度的一半)
mid_ = n//2
while mid_ > 0 :
# 2 组内插入排序
for j in range(mid_,n):
for i in range(j,0,-mid_):
if li[i-mid_]>li[i]:
li[i],li[i-mid_] = li[i-mid_],li[i]
else:
break
# 3 缩小步长一半,重复步骤2
mid_ = mid_//2
快速排序:
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
最优时间复杂度:O(nlogn)
最坏时间复杂度:O(n^2)
稳定性:不稳定
def quick(li,start,end):
if start>=end:
return
head = start
tail = end
# 1 确定基准值已经基准索引(中间位置)
index = (start+end)//2
while head<tail:
# 2 在基准值前找比基准值大的元素(向后遍历),交换并更新基准索引
while li[head]<=li[index] and head < index:
head +=1
li[head],li[index] = li[index],li[head]
index = head
# 3 在基准值后找比基准值小的元素(向前遍历),交换并更新基准索引
while li [tail]>=li[index] and tail>index:
tail-=1
li[tail],li[index] = li[index],li[tail]
index = tail
# 4 重复步骤2 3 直到首尾重合
# 至此,原序列被分成li[start:pivot_index]和li[pivot_index+1:end+1]
# 5 对前后序列重复步骤1 2 3 4
quick(li,start,index-1)
quick(li,index+1,end)
归并排序:
将数组分解最小之后,然后合并两个有序数组,基本思路是比较两个数组的最前面的数,谁小就先取谁,取了后相应的指针就往后移一位。然后再比较,直至一个数组为空,最后把另一个数组的剩余部分复制过来即可。
时间复杂度:O(nlogn)
稳定性:稳定
def merge_sort(li):
n = len(li)
while n <= 1:
return
left = li[:n//2]
right = li[n//2:]
merge_sort(left)
merge_sort(right)
# 1递归分解,分到不能分为止
li[:] = []
l_index = 0
r_index = 0
# 2返回合并,合并两个有序序列(同时遍历,选择小的放到新序列li)
while l_index<len(left) and r_index<len(right):
if left[l_index] <= right[r_index]:
li.append(left[l_index])
l_index+=1
else:
li.append(right[r_index])
r_index+=1
# 至此,某个序列遍历完了,将另一个序列的后续元素追加到li后
li+=left[l_index:]
li+=right[r_index:]