文章目录
- 一、快速排序
- 二、归并排序
一、快速排序
快速排序其实是属于交换排序,不占用额外的空间,但是由于以来与原始的排序决定交换次数,因此也是一个不稳定的排序。在最好的情况下是O(logn), 但是在最坏的情况下是O(n2)。
快排的步骤:
- 在数组中选一个基准数(通常为数组第一个);
- 将数组中小于基准数的数据移到基准数左边,大于基准数的移到右边;
- 对于基准数左、右两边的数组,不断重复以上两个过程,直到每个子集只有一个元素,即为全部有序。
假设如下的list: 3,5,7,1,4
首先设置基准值为3,则最终比3小的应该排在3的左边,比3大的应该排在3的右边。
设置一个指针i,该指针初始化指向index=1的位置,指向当前第一个大于基准值的数值,即为将来的分割点——该分割点的左边都是小于等于3的数值,该分割点的右边都是大于3的数值。
i = 1, 从index=1到最后开始依次比较
当前j指向的数值5,大于基准值,当前第一个大于基准值的值仍旧是5,所以i指针不移动,j遍历到下一个进行比较。
当前j指向的数值7,大于基准值,当前第一个大于基准值的值仍旧是5,所以i指针不移动,j遍历到下一个进行比较。
当前j指向的数值1,小于基准值,当前大于基准值的第一个值为5,index是i指向的位置。应该将1与5做交换,i向后移动一个继续指向当前大于基准值的第一个7,j遍历到下一个进行比较。
当前j指向的数值4,大于基准值,当前第一个大于基准值的值仍旧是7,所以i指针不移动,j遍历到下一个结束本次比较,将基准值与当前i指针指向的前一位做交换(当前i指针指向的是大于基准值的第一个数字,该数字之前应该是小于基准值的所有数值)。
将这次排序好的数组分成两部分:
1,3
7,5,4
在递归的调用排序
def partition(arr, low, high):
piovt = arr[low]
# 标志当前交换的位置
i = low + 1
for j in range(low+1, high):
if arr[j] < piovt:
arr[j], arr[i] = arr[i], arr[j]
i += 1
arr[i-1], arr[low] = arr[low], arr[i-1]
return i
# 快速排序函数
def quickSort(arr, low, high):
if low < high:
pi = partition(arr, low, high)
# print(pi, low, high)
quickSort(arr, low, pi - 1)
quickSort(arr, pi, high)
# 测试
a = [3,3,3,3,1]
quickSort(a, 0, len(a))
print(a)
二、归并排序
归并排序采用分治的思想,先分开,然后分而治之,在合并在一起。
拿到一个带排序的数组,不断的递归将这个数组分成左右两份,直到不可再分。然后将左右两份merge到一起。
然后将不可再分的元素进行递归排序,排序的时候需要注意,递归到后面左、右两个子数组分别都有多个元素,需要一次比较,每次填充进新数组的元素应该是左右两个子数组中最小的元素。
def merge_sort(arr):
if not arr:
return
if len(arr) == 1:
return arr
left = merge_sort(arr[: (len(arr)//2)])
right = merge_sort(arr[(len(arr) // 2):])
return merge(left, right)
def merge(left, right):
h, j, res = 0, 0, []
while h < len(left) and j < len(right):
if left[h] > right[j]:
res.append(right[j])
j += 1
else:
res.append(left[h])
h += 1
if h < len(left):
for num in left[h:]:
res.append(num)
else:
for num in right[j:]:
res.append(num)
return res