参考:https://wiki.jikexueyuan.com/project/easy-learn-algorithm/xiaohen-buy-book.html
https://note.youdao.com/ynoteshare1/index.html?id=3a18b006135addae625ccf0255303fc7&type=note
https://blog.csdn.net/qq_34228570/article/details/80024306
https://www.cnblogs.com/morewindows/archive/2011/08/22/2149612.html
【leetcode912】排序树组
常用的排序算法有:
- 桶排序
- 冒泡排序
- 快速排序
- 堆排序
- 插入排序
- 归并排序
1、桶排序:好多桶。时间复杂度为O(m+n),空间复杂度为O(max(nums)+1)
#打印出得分[5, 3, 2, 5, 8]
#10为总分数
#堆排序
def backet_sort(nums):#时间复杂度O(m+n)
res = []
size = len(nums)
if size < 2:
return nums
backet = [0 for _ in range(10+1)]
for n in nums:
backet[n] += 1
#从小到大
# for i in range(10+1):
#从大到小
for i in range(10, -1, -1):
l = backet[i]
for j in range(l):
res.append(i)
return res
# print(backet_sort([5, 3, 2, 5, 8]))
2、冒泡排序:有点像排大合照站队形;时间复杂度O(n2),空间复杂度O(1)
思路:一轮滚动确定最后一个元素(最大的元素),二轮滚动确定倒数第二个元素,从后往前确定元素
参考:https://www.cnblogs.com/SteveWesley/p/10007987.html
#冒泡排序
#def bulling_sort(nums):
class Solution:
def sortArray(self, nums):
for i in range(len(nums) - 1):
for j in range(len(nums) - i - 1):
if nums[j + 1] < nums[j]:
nums[j + 1], nums[j] = nums[j], nums[j + 1]
return nums
优化:某一趟遍历如果没有数据交换,则说明已经排好序了,因此不用再进行迭代了。用一个标记记录这个状态即可。
class Solution:
def sortArray(self, nums):
for i in range(len(nums) - 1):
flag = True
for j in range(len(nums) - i - 1):
if nums[j + 1] < nums[j]:
nums[j + 1], nums[j] = nums[j], nums[j + 1]
flag = False
if flag:
break
return nums
3、快排:找基准值,两个左右两个指针相遇;时间复杂度O(nlogn),空间复杂度为O(1).
#快排
def quick_sort(nums):
size = len(nums)
if size < 2:
return nums
pivot = nums[0]
i = 0
j = size - 1
while i < j:
if nums[j] > pivot:
j -= 1
else:
if nums[i] > pivot:
tmp = nums[i]
nums[i] = nums[j]
nums[j] = tmp
else:
i += 1
tmp = nums[i]
nums[i] = pivot
nums[0] = tmp
return quick_sort(nums[:i]) + [pivot] + quick_sort(nums[i+1:])
print(quick_sort([6, 1, 2, 7, 3, 4, 5, 10, 8]))
4、归并:先得到两个有序数组,然后合并。时间复杂度O(nlogn),空间复杂度O(n)
快排和归并排序都是用分而治之的思想去实现的。
#归并排序一句话总结:分而治之,先得到两个排序数组,然后合并为一个。
def mergesort(nums):
def merge(left, right):
res = []
i, j = 0, 0
while i < len(left) and j < len(right):
if left[i] < right[j]:
res.append(left[i])
i += 1
else:
res.append(right[j])
j += 1
res = res + left[i:] + right[j:]
return res
if len(nums) <= 1:
return nums
mid = len(nums) // 2
left = mergesort(nums[:mid])
right = mergesort(nums[mid:])
return merge(left, right)
5、插入排序:时间复杂度:O(n2) 空间复杂度:O(1)【从前往后确定元素】
对于每个未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。第一个认为已排序
- 从第一个元素开始,该元素可以认为已经被排序
- 取出下一个元素,在已经排序的元素序列中从后向前扫描
- 如果被扫描的元素(已排序)大于新元素,将该元素后移一位
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
- 将新元素插入到该位置后
- 重复步骤2~5
def insertsort(nums):
if len(nums) <= 1:
return nums
for i in range(1, len(nums)):
j = i - 1
tmp = nums[i]
while j >= 0 and tmp < nums[j]:
nums[j+1] = nums[j]
j -= 1
nums[j+1] = tmp
return nums
6、堆排序:先求出最小堆(先写出down(类似插入排序),然后取一半-1,依次4,3210),然后从后往前依次改变列表值,构成递减序列
对于数组堆:父节点为i,子节点为2i+1和2i+2
时间复杂度O(nlogn), 空间复杂度为O(1)
初始化堆的时间复杂度为O(n),堆排序的时间复杂度为O(nlogn)
def min_heapsort(nums):
def down(nums, start, n):
if len(nums) == 0:
return
i = start
j = 2 * i + 1
tmp = nums[i]
while j < n:
if j < n-1 and nums[j+1] < nums[j]:
j += 1
if nums[j] > tmp:
break
nums[i] = nums[j]
i = j
j = 2 * i + 1
nums[i] = tmp
n = len(nums)
j = n // 2 - 1
while j >= 0:
down(nums, j, n)
j -= 1
nums = min_heap(nums, 0, len(nums))
i = len(nums) - 1
while i > 0:
nums[0], nums[i] = nums[i], nums[0]
down(nums, 0, i)
i -= 1
return nums
nums = [8,1,1,2,4,4,1,3,3,2]
print(min_heapsort(nums))
第二次复习排序算法,发现归并和插入排序,还存在一些问题。
复习如下:
'''排序算法'''
'''--------------------------快排-----------------------'''
nums = [6, 3, 4, 1, 5]
def quicksort1(nums):
if len(nums) == 0:
return []
pivot = nums[0]
left = 0
right = len(nums) - 1
while left < right:
if nums[right] >= pivot:
right -= 1
else:
if nums[left] <= pivot:
left += 1
else:
nums[left], nums[right] = nums[right], nums[left]
nums[0], nums[left] = nums[left], nums[0]
return quicksort1(nums[:left]) + [pivot] + quicksort1(nums[left+1:])
# print(quicksort1(nums))
'''--------------------------冒泡-----------------------'''
def bubblingsort1(nums):
if len(nums) == 0:
return []
for i in range(1, len(nums)):
for j in range(len(nums) - i- 1):
if nums[j + 1] > nums[j]:
nums[j + 1], nums[j] = nums[j], nums[j + 1]
return nums
# print(bubblingsort1(nums))
'''--------------------------插入-----------------------'''
def insertsort1(nums):
if len(nums) <= 1:
return nums
for i in range(1, len(nums)):
j = i - 1
tmp = nums[i]
while j >= 0 and tmp < nums[j]:
nums[j+1] = nums[j]
j -= 1
nums[j+1] = tmp
return nums
# print(insertsort1(nums))
'''--------------------------归并-----------------------'''
#归并排序一句话总结:分而治之,先得到两个排序数组,然后合并为一个。
def mergesort1(nums):
if len(nums) <= 1:
return nums
mid = len(nums) // 2
left_tree = mergesort1(nums[:mid])
right_tree = mergesort1(nums[mid:])
def merge(nums1, nums2):
i = 0
j = 0
res = []
while i < len(nums1) and j < len(nums2):
if nums1[i] < nums2[j]:
res.append(nums1[i])
i += 1
else:
res.append(nums2[j])
j += 1
res += nums1[i:] + nums2[j:]
return res
return merge(left_tree, right_tree)
# print(mergesort1(nums))
'''--------------------------堆排-----------------------'''
def heapsort1(nums):
def down(nums, start, end):
tmp = nums[start]
i = start
j = 2 * i + 1
while j <= end:
if j + 1 <= end and nums[j+1] > nums[j]:
j += 1
if nums[j] <= tmp:
break
nums[i] = nums[j]
i = j
j = 2 * i + 1
nums[i] = tmp
def max_heap(nums):
i = len(nums) // 2 - 1
while i >= 0:
down(nums, i, len(nums)-1)
i -= 1
return nums
# return max_heap(nums)
nums = max_heap(nums)
i = len(nums) - 1
while i >= 1:
nums[0], nums[i] = nums[i], nums[0]
down(nums, 0, i-1)
i -= 1
return nums
print(heapsort1(nums))