1. 冒泡排序
给定一串数组,里面的较大值一个接一个地流向尾部
def bubbleSort(arr):
for i in range(len(arr)):
j = 0
while j < len(arr) - i - 1:
if arr[j] > arr[j + 1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j]
j += 1
优化版本,即能够探测到前置部分已有序,终点前移
def bubbleSort(arr):
n=len(arr)-1
while n>0:
j,end= 0,0
while j < n:
if arr[j] > arr[j + 1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j]
end= j
j += 1
n=end
2. 选择排序
每次从待排序数组中拿出最大的放到后面去
def selectSort(arr):
for i in range(len(arr), 0, -1):
maxIdx = 0
for j in range(i):
if arr[maxIdx] < arr[j]:
maxIdx = j
arr[maxIdx], arr[i - 1] = arr[i - 1], arr[maxIdx]
3. 插入排序
从头遍历数组,每次把当前位置的值插入到前面有序队列中
def insertSort(arr):
for i in range(1, len(arr)):
val, j = arr[i], i - 1
while j >= 0 and val < arr[j]:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = val
4. 希尔排序
利用间隔将数组拆分,比如数组[0,1,2,3,4,5,6,7],按照间隔4拆分为4个子集[0,4]、[1,5]、[2,6]、[3,7]分别进行插入排序,之后再利用间隔2拆分成2个子集分别进行插入排序,再利用间隔1即本身插入排序。
def shellSort(arr):
s = len(arr) // 2
while s > 0:
for i in range(0, s):
for j in range(i + s, len(arr), s):
val, k = arr[j], j - s
while k >= 0 and val < arr[k]:
arr[k + s] = arr[k]
k -= s
arr[k + s] = val
s //= 2
为了体现出和插入排序的关联,对3.插入排序加入了起点和间隔控制,嵌入到希尔排序中如下
def insertSort(arr, start, interval):
for i in range(start, len(arr)):
val, j = arr[i], i - interval
while j >= 0 and val < arr[j]:
arr[j + interval] = arr[j]
j -= interval
arr[j + interval] = val
def shellSort(arr):
s = len(arr) // 2
while s > 0:
for i in range(0, s):
insertSort(arr, i + s, s)
s //= 2
5. 归并排序
有序数组 = 有序子数组1 + 有序子数组2
def mergeSort(arr):
subMergeSort(arr, 0, len(arr))
def subMergeSort(arr, left, right):
if left >= right - 1:
return
mid = left + (right - left) // 2
subMergeSort(arr, left, mid)
subMergeSort(arr, mid, right)
tmp = arr[left:mid]
idx = 0
while idx < len(tmp):
if mid == right or tmp[idx] <= arr[mid]:
arr[left] = tmp[idx]
idx += 1
else:
arr[left] = arr[mid]
mid += 1
left += 1
6. 快速排序
将元素放到本应该有序的正确位置,即左边的都小于等于自己,右边的都大于自己
def quickSort(arr):
subQuickSort(arr, 0, len(arr))
def subQuickSort(arr, left, right):
if left >= right:
return
val = arr[left]
low, idx = left + 1, left + 1
while idx < right:
if val >= arr[idx]:
arr[low], arr[idx] = arr[idx], arr[low]
low += 1
idx += 1
arr[low - 1], arr[left] = arr[left], arr[low - 1]
subQuickSort(arr, left, low - 1)
subQuickSort(arr, low, right)
7. 堆排序
首先构造堆,之后不断从堆顶取出即可
import copy
class Myheap:
def __init__(self, arr):
self.arr = copy.deepcopy(arr)
self.len = len(arr)
self.heapSort()
def heapSort(self):
idx = 0
for i in range(self.len // 2, -1, -1):
self.downAdjust(i)
idx += 1
def downAdjust(self, pos):
left = pos * 2 + 1
val = self.arr[pos]
while left < self.len:
if left + 1 < self.len and self.arr[left] > self.arr[left + 1]:
left = left + 1
if val <= self.arr[left]:
self.arr[pos] = val
return
self.arr[pos] = self.arr[left]
pos = left
left = pos * 2 + 1
self.arr[pos] = val
def headPop(self):
val, self.arr[0] = self.arr[0], self.arr[-1]
self.arr = self.arr[:-1]
self.len -= 1
if self.len > 0:
self.downAdjust(0)
return val
def heapSort(arr):
h = Myheap(arr)
res = []
while h.len > 0:
res.append(h.headPop())
return res
8. 计数排序
统计元素出现的次数
def countSort(arr):
res = list()
if len(arr) == 0:
return res
maxV, minV = max(arr), min(arr)
tmp = [0] * (maxV - minV + 1)
print(tmp)
for v in arr:
tmp[v - minV] += 1
for idx, v in enumerate(tmp):
res += [idx + minV] * v
return res
9. 桶排序
将元素分布到不同的桶里面(可以利用hash,这里为了方便有点类似计数排序),之后每个桶分别排序,最后可以归并(这里因为分配算法最后结果有序,就没有归并)
#k表示每个桶的最大容量
def bucketSort(arr, k):
res = list()
if len(arr) == 0:
return res
maxV, minV = max(arr), min(arr)
tmp = [[] for _ in range(((maxV - minV) // k + 1))]
for v in arr:
tmp[(v - minV) // k].append(v)
for idx, v in enumerate(tmp):
r = sorted(v)
res += r
return res
10. 基数排序
# k表示十进制的最大位数
def radixSort(arr):
maxV = max(arr)
k = 1
tmp = maxV
while tmp // 10:
tmp //= 10
tmp += 1
tmp = [[] for _ in range(10)]
for i in range(k):
for j in arr:
idx = j // (pow(10, i)) % 10
tmp[idx].append(j)
start = 0
for v in tmp:
arr[start : start + len(v)] = v
start += len(v)
tmp = [[] for _ in range(10)]
时间空间复杂度
排序算法 | 平均时间复杂度 | 最好情况 | 最坏情况 | 空间复杂度 | 原地排序 | 稳定性 |
---|---|---|---|---|---|---|
冒泡排序 | O(n²) | O(n) | O(n²) | O(1) | True | 稳定 |
选择排序 | O(n²) | O(n²) | O(n²) | O(1) | True | 不稳定 |
插入排序 | O(n²) | O(n) | O(n²) | O(1) | True | 稳定 |
希尔排序 | O(nlogn) | O(nlog²n) | O(nlog²n) | O(1) | True | 不稳定 |
归并排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | False | 稳定 |
快速排序 | O(nlogn) | O(nlogn) | O(n²) | O(logn) | True | 不稳定 |
堆排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(1) | True | 不稳定 |
计数排序 | O(n+k) | O(n+k) | O(n+k) | O(k) | False | 稳定 |
桶排序 | O(n+k) | O(n+k) | O(n²) | O(n+k) | False | 稳定 |
基数排序 | O(n*k) | O(n*k) | O(n*k) | O(n+k) | False | 稳定 |
还有另一些特定场景的排序:睡眠排序、面条排序、猴子排序等等。
参考文档:
https://www.cnblogs.com/itsharehome/p/11058010.html