Python 基本排序算法:冒泡,选择,快速排序
2017-06-27
冒泡排序
算法
n 个数的序列 [a1,a2,a3,…,an]
- 从 a1 开始比较相邻元素,遍历到 an,如果第一个比第二个大,就交换他们两个
- 第一次遍历之后,最大的在最后(an)
- 从 a1 开始比较相邻元素,遍历到 a(n-1) [倒数第二个],第一个比第二个大就交换他们
- 第二次遍历之后,最后两个值 a(n-1),an, 分别是第二大的值,第一大的值
- 针对所有的元素重复以上的步骤
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较
示例
# 原始序列
[6, 8, 5, 7, 3]
# 第 1 次排序
[6, 5, 7, 3, 8]
# 第 2 次排序
[5, 6, 3, 7, 8]
# 第 3 次排序
[5, 3, 6, 7, 8]
# 第 4 次排序
[3, 5, 6, 7, 8]
# 第 5 次排序不需要移动
代码
def bubble_sort(nums):
'''
冒泡排序, 时间复杂度 O(n^2)
'''
total = len(nums)
for i in range(total-1):
for j in range(total-i-1):
if nums[j] > nums[j+1]:
nums[j], nums[j+1] = nums[j+1], nums[j]
return nums
选择排序
特点
- 选择排序是一个不稳定的排序算法
- 比较次数 O(n^2),交换次数 O(n)
- 算法的时间复杂度 O(n^2)
- 交换次数比冒泡排序少, n 值较小时,选择排序比冒泡排序快
算法
n 个数的序列 [a1,a2,a3,…,an]
- 第一次遍历,从 a1 开始,遍历到 an,找出第一个最小值位置,交换最小值与 a1
- 第二次遍历,从 a2 开始,遍历到 an,找出第二个最小值位置,交换最小值与 a2
- 第三次遍历,从 a3 开始,遍历到 an,找出第三个最小值位置,交换最小值与 a3
- 循环 n 次,完成排序
示例
# 原始序列
[6, 8, 5, 7, 3]
# 第 1 次排序,最小值3与6交换,得到
[3, 8, 5, 7, 6]
# 第 2 次排序,第二小值5与8交换,得到
[3, 5, 8, 7, 6]
# 第 3 次排序,第三小值6与8交换,得到
[3, 5, 6, 7, 8]
# 第 4,第 5 次不需要移动
代码
def select_sort(nums):
'''
选择排序, 时间复杂度 O(n^2)
'''
total = len(nums)
for i in range(total):
min = i
for j in range(i+1, total):
if nums[min] > nums[j]:
min = j
nums[min], nums[i] = nums[i], nums[min]
return nums
快速排序
算法
n 个数的序列 [a1,a2,a3,…,an]
- 选取一个中值
- 通过一趟排序将要排序的数据根据中值分成两部分,
- 其中一部分的所有数据都比另外一部分的所有数据都要小(根据中值划分)
- 然后再按此方法对这两部分数据分别进行快速排序
- 排序过程递归进行,最终完成整个数据的排序
示例
# 原始序列
[6, 8, 5, 7, 3]
# 第 1 次排序,选择 6 为中值
[6, 8, 5, 7, 3]
[6, 3, 5, 7, 8]
[5, 3, 6, 7, 8]
# 第 2 次排序,选择 5 为中值
[5, 3, 6]
[3, 5, 6]
# 第 3 次排序,选择 7 为中值
[7, 8]
# 完成排序
[3, 5, 6, 7, 8]
代码
def quick_sort(nums, left, right):
'''
快速排序, 平均时间复杂度 O(nlogn)
'''
# 递归终止条件
if left >= right:
return nums
# 选择中间值
key = nums[left]
pre_left = left
pre_right = right
while left < right:
# 选取右侧小于中间值的数值
while left < right and nums[right] >= key:
right -= 1
# 选取左侧大于中间值的数值
while left < right and nums[left] <= key:
left += 1
# 交换获取的值
nums[left], nums[right] = nums[right], nums[left]
# 交换中值与当前左右哨兵相交位置的值
nums[pre_left], nums[left] = nums[left], nums[pre_left]
# 递归二分后的子序列
quick_sort(nums, pre_left, left)
quick_sort(nums, left + 1, pre_right)
return nums
测试程序
#!/usr/bin/env python
# coding: utf-8
import random
import timeit
import functools
# ... 算法函数定义
def main():
number = 100
sample = random.sample(range(number), number)
sample = random.sample(range(number), number)
print(sample)
print('bubble sort: ', timeit.timeit(functools.partial(bubble_sort, sample), number=1))
print(sample)
sample = random.sample(range(number), number)
print(sample)
print('select sort: ', timeit.timeit(functools.partial(select_sort, sample), number=1))
print(sample)
sample = random.sample(range(number), number)
print(sample)
print('quick sort: ', timeit.timeit(functools.partial(quick_sort, sample, 0, len(sample)-1), number=1))
print(sample)
if __name__ == '__main__':
main()