常见的大O表示时间法的直观图。
冒泡排序:
这应该是最常见的排序,直接贴代码,原理在于每次循环都找到最大的值,放置于右边。时间复杂度为
n = 15
a = [10, 7, 11, 7, 18, 17, 9, 17, 0, 7, 3, 20, 20, 15, 9]
def bubble_sort(a:list):
n = len(a)
ac = a.copy()
swap_size = 1
while swap_size > 0:
swap_size = 0
for i in range(n-1):
if ac[i] > ac[i+1]:
ac[i],ac[i+1] = ac[i+1],ac[i]
swap_size += 1
n-=1
return ac
ac=bubble_sort(a)
print(ac)
快速排序
快速排序属于D&C(divide and conquer)算法中的一种,是一种分而治之的思想,D&C的思想在于两点:
1. 找出简单的基线条件(base case);
2.如何缩小问题的规模,然后使其满足基线条件;
先考虑最简单的情况,什么数组不需要排序,当数组为空或者数组只有一个数的时候,不需要排序,也就是数组的长度是小于2时候,不需要排序,这个就是基线条件。
再来如果数组包含3个呢:
[30,15,10]
从数组选择一个元素,假设是第一个数,这个元素就是基准值pivot,接下来找比这个pivot大的数放后面,小的数放前面,这个也被成为分区(partitioning)得到三个数组:
[15,10],[30],[]
1.一个由所有小于基准值的数字组成的子数组;
2.基准值;
3.一个由所有大于基准值的数组组成的子数组;
现在左边子数组是无序的,需要进一步排序[15,10],如果左边也是无序的,那么也需要接着排序,根据递归的思想,可以写出这样:
quicksort([15, 10,33])
|
quicksort([15, 10]) + [33] + quicksort([])
刚开始函数是原始数组,找到基准值,以及两边子数组,接着递归调用quicksort, 直到达到基准条件,那么就可以写出快速排序的代码了,如下:
def quicksort(array):
if len(array) < 2:
return array #←------基线条件:为空或只包含一个元素的数组是“有序”的
else:
pivot = array[0] #←------递归条件
less = [i for i in array[1:] if i <= pivot] #←------由所有小于等于基准值的元素组成的子数组
greater = [i for i in array[1:] if i > pivot] #←------由所有大于基准值的元素组成的子数组
return quicksort(less) + [pivot] + quicksort(greater)
print(quicksort([10, 5, 2, 3]))
对于时间的复杂度,贴上书的图,例如1~8数字已经排序,最坏的情况就是类似这样,栈长为n,每次涉及到的元素从7,6…1,可以表示为1…n-1,所以是
,
那么最好的情况类似这样,
每一层的时间为
, 那么总时间复杂度就是
未完待续