吃透排序算法
第一章 吃透排序算法之遍历排序
第二章 吃透排序算法之分割排序
第三章 吃透排序算法之树化排序
前言
程序等于数据结构加算法, 算法可以说是程序的灵魂, 本系列文章带大家一起领略算法中的基础排序算法. 打好排序地基, 将会快速入门算法与数据结构.
遍历排序
遍历排序是对数组遍历处理, 主要通过循环语句控制数组被分成已排序部分和乱序部分. 主要的算法分为:
- 冒泡排序
- 选择排序
- 插入排序
- 希尔排序
冒泡排序
冒泡排序是一种简单直观的排序算法. 它迭代遍历要排序的数组, 一次比较两个元素, 如果顺序错误则交换它们. 重复访问序列, 直到不需要交换, 即序列已经排序.
设n
为数组长度, 第i
轮都会使nums[n-1-i...n-1]
有序, 接着排序nums[0...i]
. python
实现如下:
nums = [1, 3, 2, 5, 4, 6]
i = 0
while i < len(nums):
j = 0
while j < (len(nums)-1)-i:
if not (nums[j] <= nums[j+1]):
nums[j], nums[j+1] = nums[j+1], nums[j]
j += 1
i += 1
print(nums)
相邻交换, 排序前后数组元素先后位置不变, 属于稳定排序, 肉眼复杂度为O(n^2).
过程中, 数序列可能已经有序, 可以利用flag
优化.
nums = [1, 3, 2, 5, 4, 6]
i = 0
while i < len(nums):
j, swap = 0, False
while j < (len(nums)-1)-i:
if not (nums[j] <= nums[j+1]):
swap = True
nums[j], nums[j+1] = nums[j+1], nums[j]
j += 1
if not swap:
break
i += 1
print(nums)
选择排序
先在未排序的序列中找到最小的元素, 存放在已排序序列的开头. 然后继续从剩余的未排序元素中寻找最小的元素, 然后将其放在已排序序列的末尾. 重复直到所有元素都排序完毕.
设n
为数组长度, 第i
轮都会使nums[0...i]
有序, 接着排序nums[i...n-1]
. python
实现如下:
nums = [1, 3, 2, 5, 4, 6]
i = 0
while i < len(nums):
j, minidx = i, i
while j < len(nums):
if nums[j] < nums[minidx]:
minidx = j
j += 1
nums[i], nums[minidx] = nums[minidx], nums[i]
i += 1
print(nums)
最小与i
交换, 排序前后可能会导致前i
的数组被交换到后面, 属于不稳定排序, 肉眼复杂度为O(n^2).
插入排序
排序序列第一个元素看做一个有序序列, 把第二个元素到最后一个元素当成是未排序序列. 遍历未排序序列, 将扫描到的每个元素插入有序序列的适当位置, 排序过程有点像冒泡排序.
设n
为数组长度, 第i
轮都会使nums[0...i]
有序, 接着排序nums[i...n-1]
. python
实现如下:
nums = [1, 3, 2, 5, 4, 6]
i = 0
while i < len(nums):
j = i
while j > 0:
if not (nums[j-1] <= nums[j]):
nums[j], nums[j-1] = nums[j-1], nums[j]
j -= 1
i += 1
print(nums)
相邻交换, 排序前后数组元素先后位置不变, 属于稳定排序, 肉眼复杂度为O(n^2).
希尔排序
为了解决插入排序的这种情况, [2,3,4,5,6,1]
此时1
要横跨数组才可以到达0
号位置. 指定gap
让数组趋近于基本有序, 属于插入排序的一种优化.
设n
为数组长度, 第i
轮都会使nums[0.gap.i]
有序, 接着排序nums[i.gap.n-1]
. python
实现如下:
nums = [2, 3, 4, 5, 6, 1]
def insert(gap):
i = 0
while i < len(nums):
j = i
while j > 0:
if not (nums[j-gap] <= nums[j]):
nums[j], nums[j-gap] = nums[j-gap], nums[j]
j -= gap
i += gap
gap = 3
while gap > 0:
insert(gap)
gap -= 1
print(nums)
gap
交换, 排序前后可能会导致前i
的数组被交换到后面, 属于不稳定排序, 肉眼复杂度为O(n^3/2).
总结
本文介绍了遍历排序的算法的实现, 包括冒泡排序以及优化, 选择排序, 插入排序以及优化的希尔排序.