def bubble_sort(nums):
for i in range(1, len(nums)):
for j in range(len(nums) - i):
if nums[j] > nums[j+1]:
nums[j], nums[j+1] = nums[j+1], nums[j]
冒泡排序有一种优化算法,在外层循环立一个flag,如果内层循环没有发生交换,说明数组已经有序,停止遍历。
def select_sort(nums):
for i in range(len(nums)-1):
# 最小数的索引
min_index = i
for j in range(i+1, len(nums)):
if nums[j] < nums[min_index]:
min_index = j
if min_index != i:
nums[i], nums[min_index] = nums[min_index], nums[i]
稳定排序要求不改变相等元素的相对位置,而选择排序选出最小元素,和前面的元素交换位置,可能会打乱相等元素的顺序。
def insert_sort(nums):
for i in range(1, len(nums)):
cur = nums[i] # 保存当前元素
j = i - 1
while j >= 0 and nums[j] > cur:
nums[j+1] = nums[j]
j -= 1
nums[j+1] = cur
插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率。
python
内置的sort()
用的就是快速排序算法步骤:
以左指针作为基准值为例:
def quick_sort(nums, l, r):
if l >= r:
return
i, j = l, r
while i < j:
while i < j and nums[j] >= nums[l]:
j -= 1
while i < j and nums[i] <= nums[l]:
i += 1
nums[i], nums[j] = nums[j], nums[i]
nums[i], nums[l] = nums[l], nums[i]
quick_sort(nums, l, i - 1)
quick_sort(nums, i + 1, r)
nums[i], nums[l] = nums[l], nums[i]
中的 i 换成 j 也可快速排序划分区间,可能将相等的值划分到不同的区间,所以不稳定。
算法步骤:
bucket
nums
中每个元素出现的次数,存入bucket
bucket
,将每个元素放在新数组的第0,1,2,……位置,每放一个元素x
,bucket[x]
减去1def count_sort(nums, max_value):
# 0 <= nums[i] <= max_value
bucket_len = max_value + 1
bucket = [0] * bucket_len
for x in nums:
bucket[x] += 1
index = 0
for i in range(bucket_len):
while bucket[i] > 0:
nums[index] = i
index += 1
bucket[i] -= 1
return nums
计数排序是用来排序0到100之间的数字的最好的算法,属于牺牲空间换时间了
原始数组:[4, 6, 7, 2, 9, 8, 3, 5]
堆是一颗完全二叉树,父节点大于左右子节点
除根节点外,节点k的父节点是k // 2 - 1
,左右子节点是2k + 1
和2k + 2
从下往上构建堆,保证根节点是最大值,每次更新节点,都需要递归的维护下层树
从下往上构建堆:
至此,二叉树形成一个完整最大堆,每个节点都不小于其左右子节点
那么,如何用最大堆进行排序呢?
答案是每次将根节点(堆首,最大值)与最后一个叶子节点(堆尾)交换,然后缩小堆的尺寸,更新堆,直到堆的尺寸为1
下面堆排序的代码:
自己造轮子(最大堆)
class Solution(object):
def heap_sort(self, nums):
l = len(nums)
# 构造大顶堆,从非叶子节点开始倒序遍历,因此是l//2 -1 就是最后一个非叶子节点
for i in range(l // 2 - 1, -1, -1):
self.build_heap(nums, i, l)
# 交换根节点与最后一个叶子节点,缩小堆的尺寸后更新堆
for i in range(l-1, -1, -1):
# nums[0]是最大值
nums[0], nums[i] = nums[i], nums[0]
self.build_heap(nums, 0, i)
return nums
def build_heap(self, nums, i, l):
"""构建大顶堆"""
# 左右子节点的下标
left, right = 2 * i + 1, 2 * i + 2
index = i
# 在当前节点和左右子节点找最大值
if left < l and nums[index] < nums[left]:
index = left
if right < l and nums[index] < nums[right]:
index = right
if i != index: # 如果发生交换,递归维护
nums[index], nums[i] = nums[i], nums[index]
self.build_heap(nums, index, l)
return nums
调用内置的heapq
import heapq
def heap_sort(nums):
heapq.heapify(nums)
res = []
for _ in range(len(nums)):
res.append(heapq.heappop(nums))
return res
堆排序属于不稳定排序和就地排序,如果有两个相等的数,有着不同的父节点,一个父节点发生交换,另一个不交换,两个相等数的顺序就发生了改变。