这里主要使用python语言实现常见的排序算法。例如:冒泡排序、选择排序、插入排序、快速排序、归并排序、希尔排序、堆排序、计数排序、桶排序、基数排序。
1、冒泡排序
原理:比较相邻的两个元素,如果前一个元素比第二个元素大,则交换两个元素
时间复杂度:平均/最差时间复杂度 O(n**2),最好时间复杂度O(n)
空间复杂度:O(1)
是否稳定:稳定
nums = [44, 3, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
n = len(nums)
for i in range(n): # 控制遍历的次数
for j in range(n - 1 - i): # 遍历没有排序完成的数
if nums[j + 1] < nums[j]: # 两两比较
nums[j], nums[j + 1] = nums[j + 1], nums[j] # 交换元素
print(nums)
# [2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
2、选择排序
原理:每次选择最小(大)的元素放到序列的开始(末尾)
时间复杂度:O(n**2)
空间复杂度:O(1)
是否稳定:稳定
nums = [44, 3, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
n = len(nums)
for i in range(n): # 进行n次选择,每次为i的位置上选择从剩下的数中选择一个最小的
minIndex = i # 假定最小元素的下标
for j in range(i + 1, n): # 遍历剩下的元素,找出最小元素的下标
if nums[minIndex] > nums[j]:
minIndex = j
nums[i], nums[minIndex] = nums[minIndex], nums[i] # 交换最小元素和当前元素
print(nums)
# [2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
3、插入排序
原理:通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入
时间复杂度:平均/最差时间复杂度 O(n**2),最好时间复杂度O(n)
空间复杂度:O(1)
稳定性:稳定
nums = [44, 3, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
n = len(nums)
for curIndex in range(1, n):
cur = nums[curIndex] # 为第i个数找到合适的位置
preIndex = curIndex - 1
while 0 <= preIndex and cur < nums[preIndex]: # 如果前面的数大于当前数,继续向前找
nums[preIndex + 1] = nums[preIndex]
preIndex -= 1
nums[preIndex + 1] = cur
print(nums)
# [2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
4、快速排序
算法原理:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
时间复杂度:平均/最好时间复杂度 O(nlog2n),最差时间复杂度O(n**2)
空间复杂度:O(nlog2n)
稳定性:不稳定
def partition(arr, left, right):
# 目的是找到pivot的正确位置:使得以pivot为分割,pivot左边的数全部小于它,pivot右边的数全部大于它
# 1、右边的数和pivot相比,如果右边的数大于pivot,继续往左边找;直到一个数小于pivot,把这个数放在数组的最左边,也就是pivot的原始位置
# 2、左边的数和pivot相比,如果左边的数小于pivot,继续往右移动;直到一个数大于pivot,把这个数放在之前右边数的位置,把pivot放在当前位置,也就是分割位置,并返回
pivot = arr[left]
while left < right:
while left < right and arr[right] >= pivot:
right -= 1
arr[left] = arr[right]
while left < right and arr[left] <= pivot:
left += 1
arr[right] = arr[left]
arr[left] = pivot
return left
def quickSort(arr, left, right):
if left < right:
partitionIndex = partition(arr, left, right)
quickSort(arr, left, partitionIndex - 1)
quickSort(arr, partitionIndex + 1, right)
return arr
nums = [44, 3, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
left = 0
right = len(nums) - 1
res = quickSort(arr=nums, left=left, right=right)
print(res)
# [2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
5、归并排序
原理:算法核心是合并两个有序数组。先局部有序,再整体有序。
时间复杂度:平均/最差/最好时间复杂度 O(nlog2n)
空间复杂度:O(n)
稳定性:稳定
def merge(nums1, nums2):
# 合并两个有序数组
res = []
len1 = len(nums1)
len2 = len(nums2)
i, j = 0, 0
while i < len1 and j < len2:
if nums1[i] < nums2[j]:
res.append(nums1[i])
i += 1
else:
res.append(nums2[j])
j += 1
if i < len1:
res += nums1[i:]
if j < len2:
res += nums2[j:]
return res
def merge_sort(nums):
# 归并排序,使用递归
n = len(nums)
if n < 2:
return nums
middle = n // 2
left = merge_sort(nums[:middle])
right = merge_sort(nums[middle:])
res = merge(left, right)
return res
nums = [44, 3, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
res = merge_sort(nums)
print(res)
# [2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]