快希选堆不稳定
一、插入排序
1.直接插入排序
是将待排序序列分为已排序区间和未排序区间,每次从未排序区间取出一个元素,在已排序区间中找到合适的位置插入,使得已排序区间仍然保持有序
时间复杂度:O(n)、O(n²)、O(n²) 【好、平均、坏】
空间复杂度:O(1)
稳定
def insertion_sort(arr):
for i in range(1, len(arr)):
key = arr[i]
j = i-1
while j >= 0 and key < arr[j]:
arr[j+1] = arr[j]
j -= 1
arr[j+1] = key
return arr
2.折半插入排序
将待排序数组分为已排序区间和未排序区间,每次从未排序区间取出一个元素,在已排序区间中使用二分查找定位其插入位置,并将其插入到相应位置,最终使整个数组排序完成
时间复杂度:O(nlog2n)、O(n²)
空间复杂度:O(1)
稳定
def binary_insertion_sort(arr):
n = len(arr)
for i in range(1, n):
left, right = 0, i - 1
while left <= right:
mid = (left + right) // 2
if arr[i] < arr[mid]:
right = mid - 1
else:
left = mid + 1
for j in range(i - 1, left - 1, -1):
arr[j + 1] = arr[j]
arr[left] = arr[i]
return arr
二分查找
# 二分查找
def binary_search(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = (left + right) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
3.希尔排序
先将整个待排序的记录序列分割成为若干子序列,分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序
具体步骤如下:
选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
按增量序列个数k,对序列进行k趟排序;
每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m的子序列,分别对各子表进行直接插入排序。仅在增量因子为1时,整个序列作为一个表来处理,表长度即为整个序列的长度。
空间复杂度:O(1)
不稳定
def shell_sort(arr):
n = len(arr)
d = n // 2 # 间隔
while d >0:
for i in range(d, n):
temp =arr[i]
j = i
while j>= d and arr[j-d] > temp:
arr[j] = arr[j-d]
j -= d
arr[j] = temp
d //=2
return arr
二、交换排序
1.冒泡排序
从后往前两两比较相邻元素的值,若为逆序,则交换它们,直至序列比较完。
时间复杂度:O(n)、O(n²)、O(n²)
空间复杂度:O(1)
稳定
def bubble_sort(arr):
n = len(arr)
for i in range(n): # 趟数
for j in range(0, n - i - 1):
if arr[j] > arr[j + 1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j]
return arr
2.快速排序
通过一趟排序将待排序的数据分割成独立的两部分,其中一部分的所有数据都要比另一部分的所有数据小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列
时间复杂度:O(nlog2n)、O(nlog2n)、O(n²)
空间复杂度:O(log2n)
不稳定
def partition(arr, 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 quick_sort(arr, low, high):
if low < high:
pivot_i = partition(arr, low, high)
quick_sort(arr, low, pivot_i - 1)
quick_sort(arr, pivot_i + 1, high)
return arr
三、选择排序
1.简单选择排序
是每一次从待排序的数据元素种选出最小(/最大)的一个元素,存放在序列的起始位置,然后再从剩余未排序的元素中继续寻找最小(/最大)的元素,以此类推,直至所有元素排序完成
时间复杂度:O(n²)
空间复杂度:O(1)
不稳定
def selection_sort(arr):
n = len(arr)
for i in range(n):
min_i = i
for j in range(i + 1, n):
if arr[j] < arr[min_i]:
min_i = j
arr[i], arr[min_i] = arr[min_i], arr[i]
return arr
2.堆排序
将待排序的元素构建成一个大顶堆(或小顶堆),然后每次将堆顶元素与堆尾元素交换,并调整堆使之满足堆的性质,重复这个过程直到整个数组有序
时间复杂度:O(nlog2n)
空间复杂度:O(1)
不稳定
def heapify(arr, n, i):
largest = i
left = 2 * i + 1
right = 2 * i + 2
if left < n and arr[left] > arr[largest]:
largest = left
if right < n and arr[right] > arr[largest]:
largest = right
if largest != i:
arr[i], arr[largest] = arr[largest], arr[i]
heapify(arr, n, largest)
def heap_sort(arr):
n = len(arr)
for i in range(n // 2 - 1, -1, -1): # 构建最大堆
heapify(arr, n, i)
for i in range(n - 1, 0, -1): # 逐步去除堆顶元素,调整堆
arr[0], arr[i] = arr[i], arr[0]
heapify(arr, i, 0)
return arr
四、归并排序
将待排序数组分成两个子数组,分别对这两个子数组进行排序,最后将已排序的子数组合并为一个有序的数组
时间复杂度:O(nlog2n)
空间复杂度:O(n)
稳定
def merge_sort(arr):
if len(arr) > 1:
mid = len(arr) // 2
left_arr = arr[:mid]
right_arr = arr[mid:]
merge_sort(left_arr)
merge_sort(right_arr)
# 合并
i = j = k = 0
while i < len(left_arr) and j < len(right_arr):
if left_arr[i] < right_arr[j]:
arr[k] = left_arr[i]
i += 1
else:
arr[k] = right_arr[j]
j += 1
k += 1
while i < len(left_arr):
arr[k] = left_arr[i]
i += 1
k += 1
while j < len(right_arr):
arr[k] = right_arr[j]
j += 1
k += 1
return arr
五、基数排序
是一种非比较型的排序算法,它将整数按位数切割成不同的数字,然后按每个位数分别比较。基数排序有两种方法:最低位优先LSD(Least Significant Digit first)和最高位优先MSD(Most Significant Digit first)。在实现过程中,LSD 的基数排序可以使用计数排序作为子排序。
具体步骤如下:
从最低位开始,依次对每一位上的数字进行稳定排序(通常使用计数排序)。
对于每一位上的排序完成后,移动到下一位,直至最高位排序完成。
时间复杂度:O(d(n+r))
空间复杂度:O(r )
稳定
def counting_sort(arr, exp):
n = len(arr)
output = [0] * n
count = [0] * 10
for i in range(n):
index = arr[i] // exp
count[index % 10] += 1
for i in range(1, 10):
count[i] += count[i - 1]
i = n - 1
while i >= 0:
index = arr[i] // exp
output[count[index % 10] - 1] = arr[i]
count[index % 10] -= 1
i -= 1
for i in range(n):
arr[i] = output[i]
def radix_sort(arr):
max_num = max(arr)
exp = 1
while max_num // exp > 0:
counting_sort(arr, exp)
exp *= 10
return arr