插⼊排序
插⼊排序(英语:Insertion Sort)是⼀种简单直观的排序算法。它的⼯作原
理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,
找到相应位置并插⼊。插⼊排序在实现上,在从后向前扫描过程中,需要反
复把已排序元素逐步向后挪位,为最新元素提供插⼊空间。
时间复杂度
最优时间复杂度:O(n) (升序排列,序列已经处于升序状态)
最坏时间复杂度:O(n )
稳定性:稳定
def insertion(li):
# 插入排序
n = len(li) #
for i in range(1,n): # 从索引1开始到n-1 因为range前包含后不包含所以就是列表长度n
for j in range(i,0,-1): # 从索引i开始到索引0位置,每次向前一步
if li[j] < li[j-1]: # 比较j 和 j前面的一位 如果j小于j-1 换位置 否则不变
li[j-1],li[j] = li[j],li[j-1]
else:
break
li = [17, 26, 93, 54, 77, 31, 44, 55, 20]
insertion(li)
print(li)
# 运行结果是:
[17,20,26,31,44,54,55,77,93]
希尔排序
将上述四⾏数字,依序接在⼀起时我们得到:[ 10 14 73 25 23 13 27 94 33
39 25 59 94 65 82 45 ]。这时10已经移⾄正确位置了,然后再以3为步⻓进
⾏排序
时间复杂度
最优时间复杂度:根据步⻓序列的不同⽽不同
最坏时间复杂度:O(n )
稳定性:不稳定
def shell_sort(li):
“”“希尔排序”""
n = len(li)
gep = n // 2
while gep >= 1: # 如果gep大于等于1式子成立进入循环
for i in range(gep,n) # 遍历gep到最后
j = i
while (j-gep) >= 0: # 如果j-gep 大于等于0循环
if li[j] < li[j-gep]: # 如果li[j] 小于li[j-gep]交换位置
li[j],li[j-gep] = li[j-gep],li[j]
j -= gep # j = j-gep
else:
break
gep //= 2 # 缩小gep一半的范围
li = [17, 26, 93, 54, 77, 31, 44, 55, 20]
shell_sort(li)
print(li)
快速排序
快速排序(英语:Quicksort),⼜称划分交换排序(partition-exchange
sort),通过⼀趟排序将要排序的数据分割成独⽴的两部分,其中⼀部分的
所有数据都⽐另外⼀部分的所有数据都要⼩,然后再按此⽅法对这两部分数
据分别进⾏快速排序,整个排序过程可以递归进⾏,以此达到整个数据变成
有序序列。
步骤为:
- 从数列中挑出⼀个元素,称为"基准"(pivot),
- 重新排序数列,所有元素⽐基准值⼩的摆放在基准前⾯,所有元素⽐基
准值⼤的摆在基准的后⾯(相同的数可以到任⼀边)。在这个分区结束
之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。 - 递归地(recursive)把⼩于基准值元素的⼦数列和⼤于基准值元素的⼦
数列排序。
递归的最底部情形,是数列的⼤⼩是零或⼀,也就是永远都已经被排序好
了。虽然⼀直递归下去,但是这个算法总会结束,因为在每次的迭代
(iteration)中,它⾄少会把⼀个元素摆到它最后的位置去。
时间复杂度
最优时间复杂度:O(nlogn)
最坏时间复杂度:O(n )
稳定性:不稳定
def quick_sort(li, start, end):
"""快速排序"""
if start >= end: # 如果开始值大于等于结束值停止
return
life = start
right = end
mid = li[start] # 选择一个元素左比较值
while life < right:
while life < right and li[right] >= mid: # 如果左边光标索引值小于右边光标的位置 并且右边的元素大于等于选择的固定元素
right -= 1 # 右边的光标向左移动一位
li[life] = li[right] # 把右边的元素赋值到左边光标的位置
while life < right and li[life] < mid: # 如果右边光标索引值小于右边的位置 并且左边的元素大于等于选择的固定元素
life += 1 # 左边的光标向右移动一位
li[right] = li[life] # 把左边的元素赋值到右边的光标的位置
li[life] = mid # 把固定的元素赋值给左边光标的位置
quick_sort(li, start, life - 1) # 把左边索引位置0到光标索引位置值减一的范围内的元素排序
quick_sort(li, life + 1, end) # 把右边光标索引位置的值+1到列表最后得范围内的元素排序
li = [17, 26, 93, 54, 77, 31, 44, 55, 20]
quick_sort(li, 0, len(li) - 1)
print(li)
归并排序
归并排序是采⽤分治法的⼀个⾮常典型的应⽤。归并排序的思想就是先递归
分解数组,再合并数组。
将数组分解最⼩之后,然后合并两个有序数组,基本思路是⽐较两个数组的
最前⾯的数,谁⼩就先取谁,取了后相应的指针就往后移⼀位。然后再⽐
较,直⾄⼀个数组为空,最后把另⼀个数组的剩余部分复制过来即可。
时间复杂度
最优时间复杂度:O(nlogn)
最坏时间复杂度:O(nlogn)
稳定性:稳定
def merger_sort(li):
"""归并排序"""
n = len(li)
if 1 == n: # 如果列表的元素剩余一个 停止拆分
return li
mid = n // 2 # 把列表以长度/2拆分成两个部分
left_sort = merger_sort(li[:mid]) # 把分开的别表左侧赋值给left_sort
right_sort = merger_sort(li[mid:]) # 把分开的别表右侧赋值给right_sort
left, right = 0, 0 # 定义变量起始位置
alist = [] # 创建列表
left_n = len(left_sort) # 定义左边列表的长度
right_n = len(right_sort) # 定义右边列表的长度
while left < left_n and right < right_n: # 左右两边的长度大于0进入循环
if left_sort[left] <= right_sort[right]: # 判断左边列表的元素小于等于右边元素
alist.append(left_sort[left]) # 把左边的元素加入到新的列表
left += 1 # 左边位置加1
else:
alist.append(right_sort[right]) # 否则把右边的元素加入到新的列表
right += 1 # 右边位置+1
alist += left_sort[left:] # 把对比完剩余的元素添加到列表
alist += right_sort[right:]
return alist
li = [17, 26, 93, 54, 77, 31, 44, 55, 20]
print(merger_sort(li))