1.冒泡排序
冒泡排序(英语:Bubble Sort)是一种简单的排序算法。它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。
"""
冒泡排序
"""
# 第一轮,依次取索引0和1、1和2,...,n-2和n-1两两比较,小的在前大的在后。一轮结束最大的在最后
# 第二轮,依次取索引0和1、1和2,...,n-3和n-2两两比较,小的在前大的在后。二轮结束次大的在倒数第二
# 第n-1轮,取索引0和1比,最小值放最前面
def bubble_sort(li):
n = len(li)
for i in range(0, n-1):
for j in range(0, n-1-i): # 每轮结束,已排序列增加,未排序列减少
if li[j] > li[j+1]:
li[j], li[j+1] = li[j+1], li[j]
li = [55, -2, 43, 91, 22, 1, 44, 90, 34]
bubble_sort(li)
print(li)
时间复杂度
- 最优时间复杂度:O(n) (表示遍历一次发现没有任何可以交换的元素,排序结束。)
- 最坏时间复杂度:O(n2)
- 稳定性:稳定
2.选择排序
选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理如下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
"""
选择排序
"""
# 第一轮,假设min_index=0,从索引1开始往后依次取值与索引0处比较,小于索引0,则最小值索引位置设置为当前索引。
# 每轮比较结束,判断min_index是否改变,改变则交换这一轮中实际的min_index和初始的min_index的值。最小值在最前面。
# 第二轮,假设min_index=1,从索引2开始依次往后取值与1处比较,找到次小值。交换次小值与本轮初始min_index=1的位置
# 重复n-1轮。
def select_sort(li):
n = len(li)
for i in range(0, n-1):
min_index = i
for j in range(i+1, n):
if li[j] < li[min_index]:
min_index = j
if min_index != i:
li[min_index], li[i] = li[i], li[min_index]
li1 = [55, -2, 43, 91, 22, 1, 44, 90, 34]
select_sort(li1)
print(li1)
时间复杂度
- 最优时间复杂度:O(n2)
- 最坏时间复杂度:O(n2)
- 稳定性:不稳定(考虑升序每次选择最大的情况)
3.插入排序
插入排序(英语:Insertion Sort)是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
"""
插入排序
"""
# 第一轮,假设索引0有序,则取索引1与0比较,大于不交换进行下一轮,小于则交换索引0和1
# 第二轮,假设索引0和1有序,则取索引2依次与索引1和索引0比,小于交换,大于进入下一轮
# 第n-1轮,假设0,1,...,n-2有序,取索引n-1依次与n-2,n-3,...,1,0比较,小于交换,大于结束
def insert_sort(li):
n = len(li)
for i in range(0, n-1): # 循环比较n-1轮
for j in range(i+1, 0, -1):
if li[j] < li[j-1]:
li[j], li[j-1] = li[j-1], li[j]
else:
break
li1 = [55, -2, 43, 91, 22, 1, 44, 90, 34]
insert_sort(li1)
print(li1)
时间复杂度
- 最优时间复杂度:O(n) (升序排列,序列已经处于升序状态)
- 最坏时间复杂度:O(n2)
- 稳定性:稳定
4.快速排序
快速排序(英语:Quicksort),又称划分交换排序(partition-exchange sort),通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
步骤为:
从数列中挑出一个元素,称为"基准"(pivot),
重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
"""
快速排序
"""
# 先假设索引0是中间值,mid = li[0],记录下来这个中间值mid
# 创建两个游标left=0,right=列表长度-1
# 取最后面的right与mid进行比较,大于mid,则right向左移,直到小于mid,这个时候,设置li[left]=li[right],
# 此时right停止移动,转而left开始比较。最后一个的元素位置空出来可以复制操作
# 即比较li[left]和mid,如果小于mid,则left向右移动,如果大于mid,则设置li[right]=li[left]
# 此时left停止移动,right开始移动,left位置又空出来允许赋值操作
# 这样一轮比较之后,left和right相遇,left=right,可以li[left]=mid,那么mid左侧都是<mid的值,右侧均>mid
# 接着left_list = li[:mid],右侧列表:right_list = li[mid:],再对其进行递归快速排序
def quick_sort(alist, start, end):
"""快速排序"""
# 递归的退出条件
if start >= end:
return
# 设定起始元素为要寻找位置的基准元素
mid = alist[start]
# low为序列左边的由左向右移动的游标
low = start
# high为序列右边的由右向左移动的游标
high = end
while low < high:
# 如果low与high未重合,high指向的元素不比基准元素小,则high向左移动
while low < high and alist[high] >= mid:
high -= 1
# 将high指向的元素放到low的位置上
alist[low] = alist[high]
# 如果low与high未重合,low指向的元素比基准元素小,则low向右移动
while low < high and alist[low] < mid:
low += 1
# 将low指向的元素放到high的位置上
alist[high] = alist[low]
# 退出循环后,low与high重合,此时所指位置为基准元素的正确位置
# 将基准元素放到该位置
alist[low] = mid
# 对基准元素左边的子序列进行快速排序
quick_sort(alist, start, low-1)
# 对基准元素右边的子序列进行快速排序
quick_sort(alist, low+1, end)
alist = [54,26,93,17,77,31,44,55,20]
quick_sort(alist,0,len(alist)-1)
print(alist)
时间复杂度
- 最优时间复杂度:O(nlogn)
- 最坏时间复杂度:O(n2)
- 稳定性:不稳定