算法--排序算法
选择排序
# 选择排序
# 选择排序思路:
# - 每次从 [i,n-1] 区间中选择最小值,放到 i 位置上
# - i 取值为 [0,n-1],因为如果最后只有一个数,则无需查询,i 取值为 [0,n-2] 即可
def select_sort(nums: list[int]):
n = len(nums)
if n <= 1:
return
for i in range(n - 1):
k = i # 用k表示最小值索引
for j in range(i + 1, n):
if nums[k] > nums[j]:
k = j
if k != i:
swap(nums, i, k)
def swap(nums: list[int], i: int, j: int):
temp = nums[i]
nums[i] = nums[j]
nums[j] = temp
nums = [1,3,4,2,3,4,5,67,12,23,34]
select_sort(nums)
print(nums)
冒泡排序
n 长度数组 nums
思路:
第一次:在 [0, n-1] 区间内冒泡
第二次:在 [0, n-2] 区间内冒泡
.....
最后一次:在 [0, 1] 区间内冒泡
伪代码:
for k from n-1 to 1:
在 [0, k] 区间内冒泡
冒泡思路:在 [0, k] 区间内冒泡
第一次:if nums[0] > nums[1] 则交换
第一次:if nums[1] > nums[2] 则交换
。。。
最后一次:if nums[k-1] > nums[k] 则交换
伪代码:
for i from 0 to k-1:
if nums[i] > nums[i+1]
swap(nums, i, i+1)
同时:n > 1 排序才有意义
def buddle_sort(nums: list[int]):
n = len(nums)
for t in range(n-1, 0, -1):
for i in range(0, t):
if nums[i] > nums[i + 1]:
swap(nums, i, i + 1)
def swap(nums: list[int], i: int, j: int):
temp = nums[i]
nums[i] = nums[j]
nums[j] = temp
nums = [1,3,4,2,3,4,5,67,12,23,34]
buddle_sort(nums)
print(nums)
public void bubble_sort(int[] nums) {
int n = nums.length;
if (n <= 1) return;
for (int t = n - 1; t >= 1; t--) {
for (int i = 0; i <= t - 1; i++) {
if (nums[i] > nums[i + 1]) {
swap(nums, i, i + 1);
}
}
}
}
private void swap(int[] nums, int i, int j) {
int t = nums[i];
nums[i] = nums[j];
nums[j] = t;
}
插入排序:
# 插入排序(类似扑克牌)
def insert_sort(nums: list[int]):
n = len(nums)
if n <= 1:
return
for k in range(1, n):
base = nums[k]
j = k - 1
while j >=0 and nums[j] > base:
nums[j + 1] = nums[j]
j = j - 1
nums[j + 1] = base
快速排序:
核心点在于寻找哨兵位,然后递归排序哨位位左侧区间和右侧区间
def quick_sort(nums: list[int]):
'''快速排序'''
quick_sort_helper(nums, 0, len(nums) - 1)
def quick_sort_helper(nums: list[int], left: int, right: int):
'''递归子方法'''
if right <= left:
return
# 哨兵位
p = part(nums, left, right)
# 递归排序哨兵左侧区间
quick_sort_helper(nums, left, p - 1)
# 递归排序哨兵右侧区间
quick_sort_helper(nums, p + 1, right)
def part(nums: list[int], left: int, right: int) -> int:
i = left
j = right
while i < j:
# 从右边往左找第一个小于哨兵的位置
while i < j and nums[j] >= nums[left]:
j = j - 1
# 从左边往右边找第一个大于哨兵的位置
while i < j and nums[i] <= nums[left]:
i = i + 1
# 交换
swap(nums, left, i)
return i
def swap(nums: list[int], i: int, j: int):
temp = nums[i]
nums[i] = nums[j]
nums[j] = temp
nums = [1,3,4,2,3,4,5,67,12,23,34]
quick_sort(nums)
print(nums)
Copilot 写的(写的清晰明了多了)
def quicksort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
left = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if x > pivot]
return quicksort(left) + middle + quicksort(right)
归并排序:
分治思想
def merge_sort(nums: list[int]):
'''归并排序'''
merge_sort_helper(nums, 0, len(nums) - 1)
def merge_sort_helper(nums: list[int], left: int, right: int):
'''递归子方法'''
if right <= left:
return
# 区分点
mid = (left + right) // 2
# 先分
merge_sort_helper(nums, left, mid)
merge_sort_helper(nums, mid + 1, right)
# 后治
merge(nums, left, mid, right)
def merge(nums: list[int], left: int, mid: int, right: int):
'''合并'''
# 临时数组
temp: list[int] = [0] * (right - left + 1)
i = left
j = mid + 1
p = 0
while i <= mid or j <= right:
if j > right or (i <= mid and nums[i] <= nums[j]):
temp[p] = nums[i]
i = i + 1
else:
temp[p] = nums[j]
j = j + 1
p = p + 1
# 拷贝数据
for t in range(left, right + 1):
nums[t] = temp[t - left]
nums = [1,3,4,2,3,4,5,67,12,23,34]
merge_sort(nums)
print(nums)
堆排序
# 使用数组 array 来表示堆(完全二叉树)的时候
# (*)i 的父节点为 (i-1)/2
# (*)i 的子节点为 i*2+1 和 i*2+2
# 堆排序流程:
# 1、建堆
# 2、将堆顶放到堆数组尾部
# 3、堆长度-1
# 4、对堆顶进行从上到下堆化操作
# 5、重复2知道堆长度为1
def heap_sort(nums: list[int]):
'''建堆(大顶堆)'''
n = len(nums)
if n <= 1:
return
# 原地堆化
for i in range(1, n):
sift_max_up(nums, i)
print(f"建堆结果 = {nums}")
# 堆顶放到末尾,依次排序
for i in range(len(nums) - 1, 0, -1):
swap(nums, 0, i)
sift_max_down(nums, i - 1)
def sift_max_up(nums: list[int], i: int):
'''从底向上堆化'''
while i > 0:
parent = (i - 1) // 2
if nums[i] > nums[parent]:
swap(nums, i, parent)
i = parent
def sift_max_down(nums: list[int], end: int):
'''从顶向下堆化'''
i = 0
while True:
p = i
left = 2 * i + 1
right = 2 * i + 2
if left > end and right > end:
break
if left <= end:
if nums[p] < nums[left]:
p = left
if right <= end:
if nums[p] < nums[right]:
p = right
if p == i:
break
swap(nums, i, p)
i = p
def swap(nums: list[int], i: int, j: int):
temp = nums[i]
nums[i] = nums[j]
nums[j] = temp
nums = [1,3,4,2,3,4,5,67,12,23,34]
heap_sort(nums)
print(nums)
计数排序:
# 算法步骤:
# (1)找出最大值Max
# (2)新建Max+1长度数组temp,统计每个数a出现的次数c,temp[a] = c
# (3)将统计结果回填到array
def count_sort(nums: list[int]):
'''计数排序'''
n = len(nums)
if n <= 1:
return
max = nums[0]
for i in range(0, n):
if max < nums[i]:
max = nums[i]
temp = [0] * (max + 1)
for i in range(0, n):
temp[nums[i]] = temp[nums[i]] + 1
p = 0
for i in range(0, max + 1):
while temp[i] > 0:
nums[p] = i
p = p + 1
temp[i] = temp[i] - 1
nums = [1,3,4,2,3,4,5,67,12,23,34]
count_sort(nums)
print(nums)
基数排序:
def radix_sort(nums: list[int]):
'''基数排序'''
n = len(nums)
if n <= 1:
return
max_num = max(nums)
exp = 1
while exp <= max_num:
radix_sort_digital(nums, exp)
exp = exp * 10
def radix_sort_digital(nums: list[int], exp):
'''按位数字排序'''
temp = [0] * 10
for i in range(0, len(nums)):
num = nums[i]
d = get_digital(num, exp)
temp[d] = temp[d] + 1
# 计算前缀和,前缀和即为元素num的最后一个下标位置
for i in range(1, 10):
temp[i] = temp[i] + temp[i - 1]
res = [0] * len(nums)
for num in nums:
d = get_digital(num, exp)
p = temp[d] - 1
res[p] = num
temp[d] = temp[d] - 1
for i in range(0, len(nums)):
nums[i] = res[i]
def get_digital(num: int, exp):
return (num // exp) % 10
nums = [1,3,4,1241241431,2241241431,2,3,4,5,67,12,23,34]
radix_sort(nums)
print(nums)