概览
插入排序
直接插入排序
将数组分为两部分,前半部分有序,后半部分无序,依次从后面取数据,插入到前面指定位置。
def insertSort(nums):
size = len(nums)
for i in range(1, size):
temp = nums[i] # 待排序的数据
count = i-1 # 代表前面有count个数据
while count >= 0 and nums[count] > temp:
nums[count+1]= nums[count]
count -= 1
nums[count+1] = temp
return nums**加粗样式**
插入排序:
时间复杂度:最好:O(n) 最差 :O(n^2)
空间复杂度:O(1)
折半插入
该方法和直接插入排序的方法有些类似,只是在搜索最佳插入位置的时候采用折半搜索,折半上搜索可以看另一篇文章:二分查找法技巧
def insert_sort_op(nums):
size = len(nums)
for i in range(1, size):
start = 0
end = i - 1
target = nums[i]
while start <= end:
mid = start + (end - start) // 2
if nums[mid] <= target:
start = mid + 1
else:
end = mid - 1
# 将 [end+1,i-1]位置的数据都往后移动一位
for i in range(i - 1, end, -1):
nums[i + 1] = nums[i]
nums[end + 1] = target
return nums
希尔排序(增量排序法)
将数据按照增量间隔分为不同的组,假如增量为k,则:
[0,k,2k,3k…]为一组,[1,k+1,2k+1,3k+1…]为一组,一共分为k组,然后分别对每一组排序。初始时,k的取值为(n/2,n/2/2…1).k每取一个值就按该分组排序一次。
图例:
def shell_sort(nums):
size = len(nums)
step = size // 2
while step > 0: # 当step == 1时,如果step / 2 = 0.5,向下取证为0,跳出训话
for i in range(step, size): # 每次从最后一组的低位开始排序即可
temp = nums[i]
index = i - step
while index >= 0 and temp < nums[index]:
nums[index + step] = nums[index]
index = index - step
nums[index + step] = temp
step //= 2
return nums
最佳情况:T(n) = O(nlog2 n)
最坏情况:T(n) = O(nlog2 n)
平均情况:T(n) =O(nlog2n)
交换排序
冒泡排序
这个是最常见的排序方法,有多种变体,下面写的是最快的一种。
def bubble_sort(nums):
size = len(nums)
step = size // 2
for i in range(size):
flag = True
for j in range(size - 2, i - 1, -1):
if nums[j] > nums[j + 1]:
nums[j], nums[j + 1] = nums[j + 1], nums[j]
flag = False
if flag:
break
return nums
复杂度分析:
最佳情况:T(n) = O(n)
最差情况:T(n) = O(n2)
平均情况:T(n) = O(n2)
快速排序
基本快排(一路快排)
快排有个特点,每次能把一个数据放到他应该在的位置上。所以快排的三个指针中的其中一个就指在这个数据的初始位置上,另外还有两个 j 是分割点,i是遍历下标。
代码如下:
def get_partition_and_sort(nums, start, end):
partition = start
# for i in range(start + 1, end + 1): # 由于使用的都是闭区间,所以要遍历到end
# nu = nums[i]
# if nums[i] < temp:
# # 如果
# nums[i], nums[partition] = nums[partition], nums[i]
# partition += 1
#
# nums[partition] = temp
# 上面的代码是错误的
# 因为partition如果指向的值是小于等于temp的值,如果在高位发现一个小于temp的值,则就把partition对应的值移到了高位
for i in range(start + 1, end + 1):
# 因为partition 指向一个小于等于temp的值,只有和partition交换后,才能保证partition+1后仍然指向小于等于 temp的值
if nums < nums[start]: # nums[start]的值值直到最后才会改变,所以一直可以当参照值
nums[i], nums[partition + 1] = nums[partition + 1], nums[i]
partition += 1
# 因为nums[partition]本来就小于temp,把它移到最左边
nums[start], nums[partition] = nums[partition], nums[start]
return partition
二路快排
二路快排的的主架构和一路快排一样:
def fast_sort(nums, start, end):
if start < end: # 这里要注意
index = get_bin_sort_partition(nums, start, end)
fast_sort(nums, start, index - 1)
fast_sort(nums, index + 1, end)
return nums
不同的是,二路快排使用两个指针:
代码如下:
def get_bin_sort_partition(nums, start, end):
i = start + 1
j = end
# 每次循环结束 i(不包含i)的左边都是大于等于nums[start]的值
# 每次循环结束 j(不包含j)的右边都是大于等于nums[start]的值
while True:
# 如果i 终止循环,则代表nums[i]的值大于nums[start]
# 学会使用短路条件,防止数组越界
while i <= end and nums[i] <= nums[start]:
i += 1
# 如果j 终止循环,则代表nums[j]的值小于nums[start]
while j >= start + 1 and nums[j] >= nums[start]:
j -= 1
if i >= j: # 碰头了就终止循环
break
# 交换后,左边大于等于nums[start],右边小于等于nums[start]
nums[i], nums[j] = nums[j], nums[i]
# while 循环在结束的时候都要对index修改,以便开启下次循环
i += 1
j -= 1
# 这里一定要和j交换
# 如果终止条件是j = i,则交换没问题
# 如果终止条件是i > j,则i指向一个大于nums[start]的值,j指向一个小于nums[start]的值
# 如果和 i 交换,则start位置就出现一个大于temp的值
nums[start], nums[j] = nums[j], nums[start]
return j
复杂度分析:
最佳情况:T(n) = O(nlogn)
最差情况:T(n) = O(n2)
平均情况:T(n) = O(nlogn)
选择排序
直接选择排序
从前往后,每次选择一个最小的,不再赘述
def select_sort(nums):
size = len(nums)
for i in range(size):
mini_index = i
for j in range(i, size): # 必须从i以后(包括i)的值里面找到最小值
if nums[j] < nums[mini_index]:
mini_index = j
nums[i], nums[mini_index] = nums[mini_index], nums[i]
return nums
堆排序
归并排序
def merge(left, right):
res = []
size_left = len(left)
size_right = len(right)
left_index = 0
right_index = 0
while left_index < size_left and right_index < size_right:
if left[left_index] < right[right_index]:
res.append(left[left_index])
left_index += 1
else:
res.append(right[right_index])
right_index += 1
if left_index == size_left:
res.extend(right[right_index:])
else:
res.extend(left[left_index:])
return res
def merge_sort(nums):
size = len(nums)
if size <= 1:
return nums
mid = size // 2
left = merge_sort(nums[:mid])
right = merge_sort(nums[mid:])
return merge(left, right)
print(merge_sort([1, 2, 3, 2, 3, 1, 3, 4, 5, 2, 2, 2, 4]))