根据时间复杂度,主流的排序算法可以分为三大类:
1. 时间复杂度为O(n2)的排序算法
- 冒泡排序
- 选择排序
- 插入排序
- 希尔排序(希尔排序比较特殊,它的性能略优于O(n2),但又比不上O(nlogn),姑且把它归为本类)
2. 时间复杂度为O(nlogn)的排序算法
- 快速排序
- 归并排序
- 堆排序
3. 时间复杂度为线性的排序算法
- 计数排序
- 桶排序
- 基数排序
排序算法还可以根据其稳定性,划分为 稳定排序和不稳定排序。即如果值相同的元素在排序后仍然保持着排序前的顺序,则这样的排序算法是稳定排序;如果值相同的元素在排序后打乱了排序前的顺序,则这样的排序算法是不稳定排序。
一.冒泡排序
1.什么是冒泡算法
- 冒泡排序的英文是bubble sort,它是一种基础的交换排序。
- 冒泡排序之所以叫冒泡排序,正因为这种排序算法的每一个元素都可以像小气泡一样,根据自身大小,一点一点地往数组的一侧移动。
- 冒泡排序是一种稳定排序,值相等的元素并不会打乱原本的顺序。
- 冒泡排序每一轮都要遍历所有元素,总过遍历(元素数量-1)轮,所以平均时间复杂度是O(n2)
- 排序原理:相邻的元素两两比较,当一个元素大于右侧相邻元素时,交换它们的位置;当一个元素小于或等于右侧元素时,位置不变。
- 算法每一轮都是从左到右比较元素,并进行单项的位置交换
def bubble_sort_v1(array = []):
for i in range(len(array) - 1):
for j in range(len(array) - i - 1):
if array[j] > array[j+1] :
# temp = array[j]
# array[j] = array[j+1]
# array[j+1] = temp
array[j], array[j+1] = array[j+1], array[j]
my_array = list ([3,4,14,1,5,6,7,8,1,-1,1,0,9,11])
bubble_sort_v1(my_array)
print(my_array)
2.冒泡排序的优化
def bubble_sort_v2(array = []):
for i in range(len(array) - 1):
# 有序标记,每一轮的初始是True
is_sorted = True
for j in range(len(array) - i - 1):
if array[j] > array[j+1] :
# temp = array[j]
# array[j] = array[j+1]
# array[j+1] = temp
array[j], array[j+1] = array[j+1], array[j]
# 有元素交换,所有不是有序的,标记变为Fasle
is_sorted = False
if is_sorted:
break
my_array = list ([3,4,14,1,5,6,7,8,1,-1,1,0,9,11])
bubble_sort_v1(my_array)
print(my_array)
def bubble_sort_v3(array = []):
# 记录最后一次交换的位置
last_exchange_idnex = 0
# 无序数列的边界, 每次比较只需要比到这里
sort_border = len(array)-1
for i in range(len(array) - 1):
# 有序标记,每一轮的初始是True
is_sorted = True
for j in range(sort_border):
if array[j] > array[j+1] :
# temp = array[j]
# array[j] = array[j+1]
# array[j+1] = temp
array[j], array[j+1] = array[j+1], array[j]
# 有元素交换,所有不是有序的,标记变为Fasle
is_sorted = False
# 把无序数列的边界更新为最后一次交换的位置
last_exchange_index = j
sort_border = last_exchange_index
if is_sorted:
break
my_array = list ([3,4,14,1,5,6,7,8,1,-1,1,0,9,11])
bubble_sort_v1(my_array)
print(my_array)
'''
sort_border 就是无序数列的边界。在每一轮排序过程中,处于sort_border之后的元素就不需要再进行比较了
'''
3.鸡尾酒排序
- 冒泡排序算法每一轮都是从左到右比较元素,并进行单项的位置交换
- 鸡尾酒排序的元素比较和交换过程是双向的。排序过程如钟摆一样,第一轮从左到右,第二轮从右到左,第三轮...
def cock_tail_sort(array = []):
for i in range(len(array) //2):
# 有序标记,每一轮的初始是True
is_sorted = True
# 奇数轮,从左到右比较和交换
for j in range(i,len(array-1) - i - 1):
if array[j] > array[j+1]:
array[j], array[j+1] = array[j + 1], array[j]
# 有元素交换,所以不是有序的, 标记为False
is_sorted = False
if is_sorted:
break
# 偶数轮之前,重新标记为True
is_sorted = True
# 偶数轮, 从右到左比较和交换
for j in range(len(array) - i - 1, i , -1):
if array[j] < array[j + 1]:
array[j], array[j + 1] = array[j + 1], array[j]
# 有元素交换, 所以不是有序的, 标记为False
is_sorted = False
if is_sorted:
break
my_array = list([3, 4, 14, 1, 5, 6, 7, 8, -1, 1, 0, 9, 11])
cock_tail_sort(my_array)
print(my_array)
'''
这代码是鸡尾酒排序的实现。 代码外层的大循环控制着所有排序回合,大循环内包含2个小循环,第1个循环从左往右比较并交换元素,第2个循环从右到左比较并交换元素。每次钟摆为一次大循环。
'''
- 鸡尾酒排序的优点是能在特定条件下,减少排序的回合数;而缺点也很明显,就是代码量几乎增加了1倍。
- 适用于大部分元素已经有序的情况下。