一、算法信息
- 直接插入排序 O(n^2),O(1),稳定
- 折半插入排序 O(n^2),O(1),稳定
- 希尔排序 时间复杂度与增量序列有关,O(1)
- 冒泡排序 O(n^2),O(1),稳定
- 快速排序 O(nlogn),O(1),不稳定
- 简单选择排序 O(n^2),O(1),不稳定
- 堆排序(大根堆) O(nlogn),O(1)
- 递归排序 O(nlogn),O(n),稳定
- 基数排序 O(d(n+k)),O(n+k),稳定
- 计数排序 O(n+k),O(n+k),稳定,(k是辅助计数数组的长度)
- 桶排序
二、真题测试
Leetcode 912. 排序数组
三、代码
3.1.直接插入排序
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
# 1.直接插入排序 O(n^2),O(1),稳定,超时
print("直接插入排序")
n = len(nums)
for i in range(1, n):
if nums[i] < nums[i - 1]:
tmp = nums[i]
j = i - 1
while j >= 0 and nums[j] > tmp:
nums[j + 1] = nums[j]
j -= 1
nums[j + 1] = tmp
return nums
3.2.折半插入排序
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
# 2.折半插入排序 O(n^2),O(1),稳定,超时
print("折半插入排序")
n = len(nums)
for i in range(1, n):
if nums[i] < nums[i - 1]:
tmp = nums[i]
l, r = 0, i - 1
# 找到第一个大于nums[i]的位置,左右闭区间,最后的l即为要求的
while l <= r:
mid = (r - l) // 2 + l
if nums[mid] > tmp:
r = mid - 1
else:
l = mid + 1
j = i - 1
while j >= l:
nums[j + 1] = nums[j]
j -= 1
nums[j + 1] = tmp
return nums
3.3.希尔排序
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
# 3.希尔排序 时间复杂度与增量序列有关,O(1),不稳定
print("希尔排序")
n = len(nums)
d = n // 2
while d >= 1:
for i in range(d, n):
if nums[i] < nums[i - d]:
tmp = nums[i]
j = i - d
while j >= 0 and nums[j] > tmp:
nums[j + d] = nums[j]
j -= d
nums[j + d] = tmp
d = d // 2
return nums
3.4.冒泡排序
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
# 4.冒泡排序 O(n^2),O(1),稳定,超时
print("冒泡排序")
n = len(nums)
for i in range(n - 1):
flag = False
for j in range(n - 1, i, -1):
if nums[j] < nums[j - 1]:
nums[j], nums[j - 1] = nums[j - 1], nums[j]
flag = True
if not flag:
break
return nums
3.5.快速排序
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
# 5.快速排序 O(nlogn),O(1),不稳定
print("快速排序")
random.shuffle(nums) # 快速排序分布均匀的元素,对于有序的排序非常不适合
def partition(arr:List[int], low:int, high:int):
if low < high:
pivot = arr[low]
while low < high:
while low < high and arr[high] >= pivot:
high -= 1
arr[low] = arr[high]
while low < high and arr[low] <= pivot:
low += 1
arr[high] = arr[low]
arr[low] = pivot
return low
def quickSort(arr:List[int], low:int, high:int):
if low < high:
pivotIndex = partition(arr, low, high)
quickSort(arr, low, pivotIndex - 1)
quickSort(arr, pivotIndex + 1, high)
quickSort(nums, 0, len(nums) - 1)
return nums
3.6.简单选择排序
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
# 6.简单选择排序 O(n^2),O(1),不稳定
print("简单选择排序")
n = len(nums)
for i in range(n - 1):
minIndex = i
for j in range(i + 1, n):
if nums[j] < nums[minIndex]:
minIndex = j
if i != minIndex:
nums[i], nums[minIndex] = nums[minIndex], nums[i]
return nums
3.7.堆排序
# ==> 基于大根堆的优先队列
class PriorityQueue:
def __init__(self, arr:List[int]):
self.arr = arr
self.size = len(arr)
# 初始化,将arr转为大根堆
self.build()
# 基本函数:上滤(以挖坑法的思维进行理解)
def up(self, index:int):
tmp = self.arr[index] # 记录根结点的值
p = (index - 1) // 2 # 父结点
while index - 1 >= 0 and self.arr[p] < tmp:
self.arr[index] = self.arr[p]
index = p
p = (index - 1) // 2
self.arr[index] = tmp
# 基本函数:下滤(以挖坑法的思维进行理解)
def down(self, index:int):
tmp = self.arr[index] # 记录根结点的值
i = 2 * index + 1 # 左子结点
while i < self.size:
# > 使i指向更大的子结点
if i + 1 < self.size and self.arr[i] < self.arr[i + 1]:
i += 1
if tmp >= self.arr[i]:
break
else:
# > 结点向下移动,坑位向上移动
self.arr[index] = self.arr[i]
index = i
i = 2 * index + 1
# > 根结点移动到最终的坑位
self.arr[index] = tmp
def build(self):
for i in range(self.size // 2, -1, -1):
self.down(i)
# 队尾增加元素
def push(self, x:int):
if len(self.arr) == self.size:
self.arr.append(0)
self.arr[self.size] = x
self.size += 1
self.up(self.size - 1)
# 队首弹出元素
def pop(self):
tmp = self.arr[0]
self.arr[0] = self.arr[self.size - 1]
self.size -= 1
self.down(0)
return tmp
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
# 7.堆排序(大根堆) O(nlogn),O(1),不稳定
print("堆排序")
n = len(nums)
pq = PriorityQueue(nums)
for i in range(n):
val = pq.pop()
nums[n - i - 1] = val
return nums
3.8.递归排序
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
# 8.递归排序 O(nlogn),O(n),稳定
print("递归排序")
n = len(nums)
arr2 = [0] * n
def merge(arr:List[int], low:int, mid:int, high:int):
i, j, k = low, mid + 1, low
for p in range(low, high + 1):
arr2[p] = arr[p]
while i <= mid and j <= high:
if arr2[i] < arr2[j]:
arr[k] = arr2[i]
i += 1
k += 1
else:
arr[k] = arr2[j]
j += 1
k += 1
while i <= mid:
arr[k] = arr2[i]
i += 1
k += 1
while j <= high:
arr[k] = arr2[j]
j += 1
k += 1
def mergeSort(arr:List[int], low:int, high:int):
if low < high:
mid = (high - low) // 2 + low
mergeSort(arr, low, mid)
mergeSort(arr, mid + 1, high)
merge(arr, low, mid, high)
mergeSort(nums, 0, n - 1)
return nums
3.9.基数排序
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
# 9.基数排序 O(d(n+k)),O(n+k),稳定[这里是通不过的,因为这个只能用于全正数]
n = len(nums)
result = [0] * n
base = 1
maxVal = max(nums)
while maxVal >= base:
# 统计该位上的各个数字的频数
cnts = [0] * 10
for num in nums:
a = (num // base) % 10
cnts[a] += 1
# 计算cnts的前缀和数组,表示当前位上小于等于a的个数(这里可以直接用cnts数组进行原地修改,但是另开一个数组思路更加清晰)
preSums = [0]
for i in range(10):
preSums.append(preSums[i] + cnts[i])
# 逆序根据preSums将数放到指定的位置
for j in range(n - 1, -1, -1):
index = (nums[j] // base) % 10
result[preSums[index + 1] - 1] = nums[j]
preSums[index + 1] -= 1
base *= 10
return result
3.10.计数排序
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
# 10.计数排序 O(n+k),O(n+k),稳定,(k是辅助计数数组的长度)
n = len(nums)
nums2 = nums.copy()
maxVal = max(nums2)
minVal = min(nums2)
cnts = [0] * (maxVal - minVal + 1)
for num in nums:
cnts[num - minVal] += 1
# 计算数字频数的前缀和
for i in range(1, len(cnts)):
cnts[i] += cnts[i - 1]
for j in range(n - 1, -1, -1):
nums[cnts[nums2[j] - minVal] - 1] = nums2[j]
cnts[nums2[j] - minVal] -= 1
return nums
3.11.桶排序
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
# 11.桶排序
print("桶排序")
minVal, maxVal = min(nums), max(nums)
if minVal == maxVal:
return nums
# 选择桶的数量
bucketCnt = int(sqrt(maxVal - minVal))
bucketWidth = (maxVal - minVal) // bucketCnt
# 创建桶
buckets = [[] for _ in range(bucketCnt)]
# 遍历,将数据加入各个桶中
for num in nums:
bucketIndex = (num - minVal) // bucketWidth
bucketIndex = bucketIndex if bucketIndex < bucketCnt else bucketCnt - 1
buckets[bucketIndex].append(num)
# 桶内排序并输出
result = []
for i in range(bucketCnt):
buckets[i].sort()
result += buckets[i]
return result