一、冒泡排序
def bubbleSort(arr):
n = len(arr)
# 遍历所有数组元素
for i in range(n): # 从0到n
# Last i elements are already in place
for j in range(n - 1 - i): # 从0到n - 1 - i
# 如果前一个大于后一个,进行交换
if arr[j] > arr[j + 1]:
# 直接将两个变量放到元组中,再通过元组按照index进行赋值的方式进行重新赋值给两个变量,来完成交换
arr[j], arr[j + 1] = arr[j + 1], arr[j]
'''
# 相当于:
temp = arr[j]
arr[j] = arr[j+1]
arr[j+1] = temp
'''
# 测试
arr = [64, 34, 25, 12, 22, 11, 90]
bubbleSort(arr)
print("排序后的数组:")
print(arr)
# [11, 12, 22, 25, 34, 64, 90]
复杂度(默认为时间复杂度)(默认为最坏情况):O(n²)
空间复杂度为:O(1)
二、选择排序
def selectionSort(arr):
n = len(arr)
# 遍历所有数组元素
for i in range(n - 1): # 从0到n-1
min = i
for j in range(i + 1, n): # 与后面的每一个数进行比较,记下数字最小的下标min
if arr[min] > arr[j]: # 如果当前arr[min]比后面的大
min = j # 使后面的(i+1)为min,(i+1)即j
# 将arr[i+1]到array[n]中最小的arr[min],与arr[i]交换
arr[min], arr[i] = arr[i], arr[min]
# 测试
arr = [64, 34, 25, 12, 22, 11, 90]
selectionSort(arr)
print("排序后的数组:")
print(arr)
# [11, 12, 22, 25, 34, 64, 90]
时间复杂度:O(n²)
空间复杂度为:O(1)
三、快速排序
1.算法简介
快速排序采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。
该方法的基本思想是:
1.先从数列中取出一个数作为基准数。(这里选择第一个数)
2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3.再对左右区间重复第二步,直到各区间只有一个数。
其执行流程可以概括为:每一趟排序选择当前所有子序列的一个关键字(通常是第一个)作为枢轴量,将子序列中比枢轴量小的移到枢轴前边,比枢轴大的移到枢轴后边,具体过程是一个交替扫描和交换的过程。当本趟所有子序列都被枢轴以上述规则划分完毕后会得到新的一组更短的子序列,它们会成为下一趟划分的初始序列集。
2.执行流程
原始序列:
49 38 65 97 76 13 27 49
i j (i和j开始时分别指向头、尾)
进行第一趟快速排序:
以第一个数49作为枢轴pivot,整个过程是一个交替扫描和交换的过程
1)使用j,从序列最右端开始扫描,直到遇到比枢轴49更小的数27,j停在这里。
49 38 65 97 76 13 27 49
i j
2)将27交换到序列前端i的位置。
27 38 65 97 76 13 49
i j
3)使用i,变换扫描方向,从前向后扫描,直到遇到比枢轴49大的数65,i停在这里。
27 38 65 97 76 13 49
i j
4)将65交换到序列后端j的位置。
27 38 97 76 13 65 49
i j
5)使用i,变换扫描方向...
9)使用j,变换扫描方向,从后向前扫描,直到遇到比枢轴49小的数,当扫描到i与j相遇时,说明扫描过程结束了。
27 38 13 76 97 65 49
ij
10)此时i等于j的这个位置就是枢轴49的最终位置,将49放入这个位置,第一趟快速排序结束。
27 38 13 49 76 97 65 49
ij
第一趟划分后,将原来的序列以49为枢轴,划分为两部分,49左边的数都小于或等于它,右边的数都大于或等于它。
接下来按照同样的方法对序列{27 38 13}和序列{76 97 65 49}分表进行排序。
经过几趟这样的划分,最终会的到一个有序的序列。
3.Python代码
def quick_sort(nums: list, left: int, right: int) -> None:
if left < right:
# 开始时,i指向头,j指向尾
i = left
j = right
# 取第一个元素为枢轴pivot
pivot = nums[left]
# 当i和j没有相遇时
while i != j:
# 交替扫描和交换
# 从右往左找到第一个比枢轴量小的元素,交换位置
while j > i and nums[j] > pivot:
j -= 1
if j > i:
# 如果找到了,进行元素交换
nums[i] = nums[j]
# i向后移一位准备扫描
i += 1
# 从左往右找到第一个比枢轴量大的元素,交换位置
while i < j and nums[i] < pivot:
i += 1
if i < j:
nums[j] = nums[i]
# j向前移一位准备扫描
j -= 1
# 至此完成一趟快速排序,枢轴pivot的位置已经确定好了,就在i位置上(i和j值相等),将枢轴pivot放在这里
nums[i] = pivot
# 递归调用函数,以i为枢轴拆分为左右两个子序列元素交换(传入的还是整个数组,只是对其中一部分进行了排序)
# 进行左边序列的排序
quick_sort(nums, left, i-1)
# 进行右边序列的排序
quick_sort(nums, i+1, right)
# 测试代码
import random
data = [random.randint(-100, 100) for _ in range(10)]
'''
相当于
data = []
for i in range(10):
i = random.randint(-100, 100)
data.append(i)
'''
print(data)
quick_sort(data, 0, len(data) - 1)
print(data)
平均时间复杂度:O(nlogn)
最坏时间复杂度:O(n²)
空间复杂度:O(logn)