目录标题
插入排序
- 基本思想:将一个元素插入到一个有序序列中,继而得到一个有序的元素个数加一的新序列.
直接插入排序
- 基本操作:将第i个元素插入前面i-1个已经排好序的序列中.
- 示意图:举例序列(21,25,49,25,16,8)
python
复制代码
# 4-1.直接插入排序
class InsertSort:
def __init__(self, items):
self.items = items
def insertSort(self):
# 直接插入排序
# 从第二个元素开始排序
for i in range(1,len(self.items)):
# 获取第n个元素
temp = self.items[i]
j = i-1
while j >= 0 and temp < self.items[j]:
self.items[j+1] = self.items[j]
j -= 1
self.items[j+1] = temp
if __name__ == '__main__':
# 4-1.直接插入排序
print('直接插入排序:')
nums = [21, 25, 49, 25, 16, 8]
print(f"排序前情况:{nums}")
select = InsertSort(nums)
select.insertSort()
print(f"直接插入排序后情况:{nums}")
- 最好与最坏的直接插入排序法情况
- 顺序排序:总的比较次数n-1次;总的移动次数2(n-1)次.
- 逆序排序:总的比较次数(n-1)(n+2)/2;总的移动次数(n-1)(n+4)/2次.
- 时间复杂度: O ( n 2 ) \mathcal{O}(n^2) O(n2)
折半插入排序
- 基本操作:在直接插入排序中,可以在前半部分的有序序列中采用折半查找的方法以提高查找速度.
- 折半插入排序在次数比较上减少了很多,但是时间复杂度仍然还是: O ( n 2 ) \mathcal{O}(n^2) O(n2)
- 折半插入示意图
python
复制代码
# 4-2.折半插入排序
class BinaryInsertSort:
def __init__(self, items):
self.items = items # 初始化待排序数组
def binaryInsertSort(self):
"""折半插入排序"""
for i in range(1, len(self.items)): # 从第二个元素开始遍历
temp = self.items[i] # 当前待插入元素
low = 0
high = i - 1 # 已排序区间的右边界
# ---------- 折半查找插入位置 ----------
while low <= high:
mid = (low + high) // 2
if self.items[mid] > temp:
high = mid - 1 # 插入点在左半区
else:
low = mid + 1 # 插入点在右半区
# 最终插入位置为 high + 1
# ---------- 元素后移 & 插入 ----------
for j in range(i - 1, high, -1): # 将 high+1 到 i-1 的元素后移
self.items[j + 1] = self.items[j]
self.items[high + 1] = temp # 插入元素到正确位置
if __name__ == '__main__':
# 4-2.折半插入排序
print('折半插入排序:')
nums = [21, 25, 49, 25, 16, 8]
print(f"排序前情况:{nums}")
select = BinaryInsertSort(nums)
select.binaryInsertSort()
print(f"折半插入排序后情况:{nums}")
print()
希尔排序
- 基本操作
- 先取一个小于n的整数d作为第一个增量,把序列的全部元素分为d个组.
- 在各组内部进行直接插入排序.
- 再取第二个增量d1(小于d),分为d1个组,在组内进行直接插入排序.
- 重复,直至增量为1,完成排序.
- 希尔排序示意图

python
复制代码
# 4-3.希尔排序
class ShellSort:
def __init__(self, items):
self.items = items
def shellSort(self):
if self.items is None or len(self.items) <= 1:
return
length = len(self.items)//4
while length > 0:
for left in range(len(self.items)):
right = left - length
while right >= 0:
if self.items[right] > self.items[right + length]:
self.items[right], self.items[right+length] = self.items[right+length],self.items[right]
right = right - length
length //= 2
if __name__ == '__main__':
# 4-3.希尔排序
print('希尔排序:')
nums = [46, 55, 13, 42, 94, 17, 5, 70]
shell = ShellSort(nums)
print(f"排序前情况:{nums}")
shell.shellSort()
print(f"希尔排序后情况:{nums}")
print()
- 运行情况

交换排序
- 基本思想:根据序列中两个元素关键字的比较结果,判断是否需要交换元素在序列中的位置.
冒泡排序
- 核心思想:
- 反复扫描待排序序列,在扫描的过程中顺次比较相邻的两个元素的大小,若为逆序则交换位置.
- 每一轮排序都将当前未排序的序列中的最大值下沉到最底部,直至得到有序序列.
- 一轮冒泡排序示意图
python
复制代码
# 5-1.冒泡排序
class BubbleSort:
def __init__(self, items):
self.items = items
def bubbleSort(self):
if self.items is None or len(self.items) == 0:
return
for i in range(len(self.items)):
for j in range(len(self.items)-1-i):
if self.items[j] > self.items[j+1]:
self.items[j],self.items[j+1] = self.items[j+1], self.items[j]
if __name__ == '__main__':
# 5-1.冒泡排序
print('冒泡排序:')
nums = [21, 25, 49, 25, 16, 8]
bubble = BubbleSort(nums)
print(f"排序前情况:{nums}")
bubble.bubbleSort()
print(f"冒泡排序后情况:{nums}")
print()
快速排序
- 核心思想
- 是对冒泡排序的一种改进.
- 算法以某一元素v作为基准,先将待排序序列分为前后两段(前段元素要求均小于v,后段元素要求均大于v),
- 再分别对前段、后段元素进行快速排序,利用递归调用进行实现,
- 重复进行,直至得到一个长度为n的有序序列.
- 一轮快速排序示意图

powershell
复制代码
# 5-2.快速排序
class QuickSort:
def __init__(self, items):
self.items = items
def quickSort(self):
"""快速排序入口方法"""
self._sort(0, len(self.items) - 1)
return self.items
def _sort(self, left, right):
"""递归排序核心逻辑"""
if left < right:
pivot_index = self._partition(left, right)
self._sort(left, pivot_index - 1) # 递归处理左半部分
self._sort(pivot_index + 1, right) # 递归处理右半部分
def _partition(self, left, right):
"""划分操作"""
pivot = self.items[right] # 选择最后一个元素为基准值
i = left - 1 # 小于基准值的分界指针
for j in range(left, right):
if self.items[j] <= pivot:
i += 1
self.items[i], self.items[j] = self.items[j], self.items[i] # 交换元素
# 将基准值放到正确位置
self.items[i + 1], self.items[right] = self.items[right], self.items[i + 1]
return i + 1 # 返回基准值的最终位置
if __name__ == '__main__':
# 5-2.快速排序
print('快速排序:')
nums = [21, 25, 49, 25, 16, 8, 34]
quick = QuickSort(nums)
print(f"排序前情况:{nums}")
quick.quickSort()
print(f"快速排序后情况:{nums}")
print()
归并排序
- 核心思想
- 将两个或两个以上有序序列合并成一个新的有序序列.
- 初始序列含有n个元素,将每个元素看成n个有序子序列.
- 进行两两归并,得到n/2的有序序列.
- 递归调用,在之前的基础上,不断地进行两两归并.
- 直到得到一个长度为n的有序序列.
- 上述方法也成为2-路归并排序.
- 2-路归并排序
python
复制代码
# 6.归并排序
class mergeSort:
def merge(self, left, right):
# 把多个有序序列合并成一个有序序列
result = []
left_index = 0
right_index = 0
while left_index < len(left) and right_index < len(right):
if left[left_index] <= right[right_index]:
result.append(left[left_index])
left_index += 1
else:
result.append(right[right_index])
right_index += 1
# while循环结束,把剩下的数据添加进去
result += right[right_index:]
result += left[left_index:]
return result
def mergeSort(self, items):
# 归并排序
n = len(items)
# 递归返回
if n == 1:
return items
# 将数据分为左右两部分
mid = n // 2
left = items[:mid]
right = items[mid:]
# 递归拆分
left_sort = self.mergeSort(left)
right_sort = self.mergeSort(right)
return self.merge(left_sort, right_sort)
if __name__ == '__main__':
print('PyCharm')
# 6.归并排序
print('归并排序:')
nums = [19, 13, 5, 27, 1,26, 31, 16]
merge = mergeSort()
print(f"排序前情况:{nums}")
nums = merge.mergeSort(nums)
print(f"归并排序后情况:{nums}")
print()
- 时间复杂度: O ( n log 2 n ) \mathcal{O}(n \log_2 n) O(nlog2n)
时间复杂度对比
最好情况
- 直接插入排序 O ( n ) \mathcal{O}(n) O(n)
- 折半插入排序 O ( n 2 ) \mathcal{O}(n^2) O(n2)
- 希尔排序 O ( n log 2 n ) \mathcal{O}(n \log_2 n) O(nlog2n)
- 冒泡排序 O ( n ) \mathcal{O}(n) O(n)
- 快速排序 O ( n log 2 n ) \mathcal{O}(n \log_2 n) O(nlog2n)
- 归并排序 O ( n log 2 n ) \mathcal{O}(n \log_2 n) O(nlog2n)
平均情况
- 直接插入排序 O ( n 2 ) \mathcal{O}(n^2) O(n2)
- 折半插入排序 O ( n 2 ) \mathcal{O}(n^2) O(n2)
- 希尔排序 O ( n 3 / 2 ) \mathcal{O}(n^{3/2}) O(n3/2)
- 冒泡排序 O ( n 2 ) \mathcal{O}(n^2) O(n2)
- 快速排序 O ( n log 2 n ) \mathcal{O}(n \log_2 n) O(nlog2n)
- 归并排序 O ( n log 2 n ) \mathcal{O}(n \log_2 n) O(nlog2n)
最坏情况
- 直接插入排序 O ( n 2 ) \mathcal{O}(n^2) O(n2)
- 折半插入排序 O ( n 2 ) \mathcal{O}(n^2) O(n2)
- 希尔排序 O ( n 2 ) \mathcal{O}(n^2) O(n2)
- 冒泡排序 O ( n 2 ) \mathcal{O}(n^2) O(n2)
- 快速排序 O ( n 2 ) \mathcal{O}(n^2) O(n2)
- 归并排序 O ( n log 2 n ) \mathcal{O}(n \log_2 n) O(nlog2n)
空间复杂度对比
- 直接插入排序 O ( 1 ) \mathcal{O}(1) O(1)
- 折半插入排序 O ( 1 ) \mathcal{O}(1) O(1)
- 希尔排序 O ( 1 ) \mathcal{O}(1) O(1)
- 冒泡排序 O ( 1 ) \mathcal{O}(1) O(1)
- 快速排序 O ( log 2 n ) ∼ O ( n ) \mathcal{O}(\log_2 n) \sim \mathcal{O}(n) O(log2n)∼O(n)
- 归并排序 O ( n ) \mathcal{O}(n) O(n)