问题来源:排序数组
问题描述:给你一个整数数组 nums,将该数组升序排列。
例子:
输入:nums = [5,2,3,1]
输出:[1,2,3,5]
思路:这里没有什么好说的,有十种常见的排序算法。参考自@Sweetiee
1. 冒泡排序( O ( n 2 ) O(n^2) O(n2),稳定)
顾名思义,冒泡排序需要遍历n次,每次遍历都取出剩余元素中的最大值,最大值如同泡沫一样缓缓上升。
# 输入
a = [5, 4, 2, 3, 1]
# 冒泡排序
def bubble_sort(a):
# 确定第i个最小值
for i in range(len(a)):
# 逐次交换比较,挑选出a[i:]中的最小值
for j in range(len(a)-1, i, -1):
if a[j] < a[j-1]:
a[j], a[j-1] = a[j-1], a[j]
return a
从程序可以看出来,只用到常数额外空间,因此,额外空间复杂度为 O ( 1 ) O(1) O(1)。
2. 选择排序( O ( n 2 ) O(n^2) O(n2),不稳定)
选择排序意味着,同样进行n次遍历,每次遍历选出其中最小值。
# 输入
a = [5, 4, 2, 3, 1]
# 选择排序
def selection_sort(a):
# 第i个最小值
for i in range(len(a)):
# 在a[i:]中选出最小值
min_ind = i
for j in range(i, len(a)):
if a[j] < a[min_ind]:
min_ind = j
a[i], a[min_ind] = a[min_ind], a[i]
return a
3. 插入排序( O ( n 2 ) O(n^2) O(n2),稳定)
同样n次遍历,每次遍历中,从未排序部分拿出一个数,依次与排序部分从末尾进行比较,如果拿出来的数小于排序部分的末尾,则交换;否则,停止。
# 输入
a = [5, 4, 2, 3, 1]
# 插入排序
def insertion_sort(a):
# a[:i+1]为有序部分
for i in range(len(a)-1):
# 取出a[i+1],通过从大到小逐次比较插入有序部分
for j in range(i, -1, -1):
if a[j+1] < a[j]:
a[j+1], a[j] = a[j], a[j+1]
else:
break
return a
4. 堆排序( O ( n l o g n ) O(nlogn) O(nlogn),稳定)
通过创建最大堆并维护最大堆,每次弹出堆顶,直至堆空。
# 输入
a = [5, 4, 2, 3, 1]
# 最大堆
class maxHeap:
# 初始化堆
def __init__(self):
self.heap = []
# 元素a[i]上浮
def bubble(self, i):
if i == 0:
return
parent = (i-1) // 2
if self.heap[i] > self.heap[parent]:
self.heap[i], self.heap[parent] = self.heap[parent], self.heap[i]
self.bubble(parent)
# 元素a[i]下沉
def sink(self, i, n):
left = 2 * i + 1
right = 2 * i + 2
largest = i
if left < n and self.heap[largest] < self.heap[left]:
largest = left
if right < n and self.heap[largest] < self.heap[right]:
largest = right
if largest != i:
self.heap[i], self.heap[largest] = self.heap[largest], self.heap[i]
self.sink(largest, n)
# 根据数组a创建最大堆
def buildHeap(self, a):
self.heap = a
for i in range(len(a)):
self.bubble(i)
# 将最大堆堆顶与最后一个元素交换,重新维护最大堆性质
def heapSort(self):
for i in range(len(self.heap)-1, -1, -1):
self.heap[i], self.heap[0] = self.heap[0], self.heap[i]
self.sink(0, i)
return self.heap
# 堆排序的运用
obj = maxHeap()
obj.buildHeap(a)
print(obj.heapSort())
5. 归并排序
先递归,再处理。定义merge函数。
# 输入
a = [5, 4, 2, 3, 1]
# 归并排序
## merge函数
def merge(a, b):
temp = []
i, j = 0, 0
while i < len(a) and j < len(b):
if a[i] < b[j]:
temp.append(a[i])
i += 1
else:
temp.append(b[j])
j += 1
if i < len(a):
temp.extend(a[i:])
if j < len(b):
temp.extend(b[j:])
return temp
## 主函数
def mergeSort(a):
if len(a) <= 1:
return a
mid = len(a) // 2
left = mergeSort(a[:mid])
right = mergeSort(a[mid:])
return mergeSort(left, right)
6. 快速排序
先处理,再递归。
# 输入
a = [5, 4, 2, 3, 1]
# 快速排序
def quickSort(a):
if len(a) <= 1:
return a
pivot = a[0]
left = [ele for ele in a if ele < pivot]
middle = [ele for ele in a if ele == pivot]
right = [ele for ele in a if ele > pivot]
return quickSort(left) + middle + quickSort(right)
7. 希尔排序
又名递减增量排序算法。
# 输入
a = [5, 4, 2, 3, 1]
# 希尔排序
def shellSort(a):
if len(a) <= 1:
return a
gap = len(a) // 2
while gap > 0:
# 给定gap,做插入排序
for i in range(gap, len(a)):
j = i
while j >= gap and a[j-gap] > a[j]:
a[j-gap], a[j] = a[j], a[j-gap]
j -= gap
gap //= 2
return a
8. 桶排序
非常快的算法,但是需要元素范围较小~
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
num_range = 50000
backet = [0] * (2 * num_range + 1)
for num in nums:
backet[num + num_range] += 1
j = 0
for i in range(len(backet)):
if backet[i]:
while backet[i]:
nums[j] = i - num_range
j += 1
backet[i] -= 1
return nums
9. 计数排序
计数排序也是一种桶排序。
10. 基数排序
基数排序相当于多轮桶排序,具体来说,就是从低到高逐位进行桶排序(需要确保元素值为非负数)。
参考@wangzaistoneRightNow
# 输入
a = [5, 4, 2, 3, 1]
# 基数排序
def radixSort(a, d): # d为最高位数,比如,550是三位数
for k in range(d): # d轮桶排序
s = [[] for i in range(10)]
for num in a:
m = int(num / (10 ** k) % 10) # 提取出数值的第i位数
s[m].append(num)
a = [j for i in a for j in i] # 第i位排序结果
return a