参考书籍:算法导论(第三版)
基础知识
插入排序
插入排序算法
INSERTION-SORT(A)
输入:一个包含n个元素的数组A
输出:按非降序排列的数组A(从小到大排序)
for j = 2 to A.length // 外层循环:遍历数组中的每一个元素,从第二个元素开始
key = A[j] // 保存当前需要插入的元素A[j]的值
// 在已排序的序列A[1..j-1]中找到合适的位置,将A[j]插入其中
i = j - 1
while i > 0 and A[i] > key // 内层循环:从后往前遍历已排序序列
A[i + 1] = A[i] // 如果A[i]比A[j]大,将A[i]向后移动一个位置
i = i - 1
A[i + 1] = key // 将A[j]插入到找到的合适位置
// 注:在每次外层循环结束后,A[1..j]都是已排序的子数组
def insertion_sort(A):
n = len(A) # 获取数组A的长度n
for j in range(1, n): # 外层循环:遍历数组中的每一个元素,从第二个元素开始
key = A[j] # 保存当前需要插入的元素A[j]的值
# 在已排序的序列A[0..j-1]中找到合适的位置,将A[j]插入其中
i = j - 1
while i >= 0 and A[i] > key: # 内层循环:从后往前遍历已排序序列
A[i + 1] = A[i] # 如果A[i]比A[j]大,将A[i]向后移动一个位置
i = i - 1
A[i + 1] = key # 将A[j]插入到找到的合适位置
return A # 返回按非降序排列的数组A
# 示例使用:
if __name__ == "__main__":
A = [5, 2, 4, 6, 1, 3]
print("原始数组A:", A)
sorted_A = insertion_sort(A)
print("插入排序后的数组A:", sorted_A)
归并培训
归并排序算法
MERGE(A, p, q, r)
输入:一个包含n个元素的数组A,下标范围为p到r,其中p <= q < r
输出:将数组A的子数组A[p..q]和A[q+1..r]合并为一个有序数组
n_1 = q - p + 1 // 计算左子数组A[p..q]的长度
n_2 = r - q // 计算右子数组A[q+1..r]的长度
let L[1..n_1+1] and R[1..n_2+1] be new arrays // 创建两个新数组L和R,用于存储子数组A[p..q]和A[q+1..r]
for i = 1 to n_1 // 将左子数组A[p..q]的元素复制到数组L
L[i] = A[p + i - 1]
for j = 1 to n_2 // 将右子数组A[q+1..r]的元素复制到数组R
R[j] = A[q + j]
L[n_1 + 1] = inf // 设置哨兵元素,用于标识数组L的结束
R[n_2 + 1] = inf // 设置哨兵元素,用于标识数组R的结束
i = 1 // 初始化指针i,指向数组L的第一个元素
j = 1 // 初始化指针j,指向数组R的第一个元素
for k = p to r // 遍历数组A的下标范围[p, r]
if L[i] <= R[j]: // 比较数组L和R中指针位置的元素
A[k] = L[i] // 将较小的元素放入数组A中的位置k
i = i + 1 // 移动指针i,指向数组L中的下一个元素
else
A[k] = R[j] // 将较小的元素放入数组A中的位置k
j = j + 1 // 移动指针j,指向数组R中的下一个元素
MERGE-SORT(A, p, r)
输入:一个包含n个元素的数组A,下标范围为p到r
输出:按非降序排列的数组A(从小到大排序)
if p < r:
q = floor[(p + r) / 2] // 计算数组的中间位置
MERGE-SORT(A, p, q) // 递归地对左半部分进行归并排序
MERGE-SORT(A, q+1, r) // 递归地对右半部分进行归并排序
MERGE(A, p, q, r) // 合并左右两个有序子数组
MERGE(A, p, q, r)
输入:一个包含n个元素的数组A,下标范围为p到r,其中p <= q < r
输出:将数组A的子数组A[p..q]和A[q+1..r]合并为一个有序数组
n_1 = q - p + 1 // 计算左子数组A[p..q]的长度
n_2 = r - q // 计算右子数组A[q+1..r]的长度
let L[1..n_1+1] and R[1..n_2+1] be new arrays // 创建两个新数组L和R,用于存储子数组A[p..q]和A[q+1..r]
for i = 1 to n_1 // 将左子数组A[p..q]的元素复制到数组L
L[i] = A[p + i - 1]
for j = 1 to n_2 // 将右子数组A[q+1..r]的元素复制到数组R
R[j] = A[q + j]
L[n_1 + 1] = inf // 设置哨兵元素,用于标识数组L的结束
R[n_2 + 1] = inf // 设置哨兵元素,用于标识数组R的结束
i = 1 // 初始化指针i,指向数组L的第一个元素
j = 1 // 初始化指针j,指向数组R的第一个元素
for k = p to r // 遍历数组A的下标范围[p, r]
if L[i] <= R[j]: // 比较数组L和R中指针位置的元素
A[k] = L[i] // 将较小的元素放入数组A中的位置k
i = i + 1 // 移动指针i,指向数组L中的下一个元素
else
A[k] = R[j] // 将较小的元素放入数组A中的位置k
j = j + 1 // 移动指针j,指向数组R中的下一个元素
MERGE-SORT(A, p, r)
输入:一个包含n个元素的数组A,下标范围为p到r
输出:按非降序排列的数组A(从小到大排序)
if p < r:
q = floor[(p + r) / 2] // 计算数组的中间位置
MERGE-SORT(A, p, q) // 递归地对左半部分进行归并排序
MERGE-SORT(A, q+1, r) // 递归地对右半部分进行归并排序
MERGE(A, p, q, r) // 合并左右两个有序子数组
def merge(A, p, q, r):
n1 = q - p + 1 # 计算左子数组A[p..q]的长度
n2 = r - q # 计算右子数组A[q+1..r]的长度
L = A[p : p + n1] # 创建新数组L,复制左子数组A[p..q]
R = A[q + 1 : q + 1 + n2] # 创建新数组R,复制右子数组A[q+1..r]
L.append(float('inf')) # 设置哨兵元素,用于标识数组L的结束
R.append(float('inf')) # 设置哨兵元素,用于标识数组R的结束
i = j = 0 # 初始化指针i和j,分别指向数组L和R的第一个元素
for k in range(p, r + 1): # 遍历数组A的下标范围[p, r]
if L[i] <= R[j]: # 比较数组L和R中指针位置的元素
A[k] = L[i] # 将较小的元素放入数组A中的位置k
i += 1 # 移动指针i,指向数组L中的下一个元素
else:
A[k] = R[j] # 将较小的元素放入数组A中的位置k
j += 1 # 移动指针j,指向数组R中的下一个元素
def merge_sort(A, p, r):
if p < r:
q = (p + r) // 2 # 计算数组的中间位置
merge_sort(A, p, q) # 递归地对左半部分进行归并排序
merge_sort(A, q + 1, r) # 递归地对右半部分进行归并排序
merge(A, p, q, r) # 合并左右两个有序子数组
# 示例使用:
if __name__ == "__main__":
A = [5, 2, 4, 6, 1, 3]
print("原始数组A:", A)
merge_sort(A, 0, len(A) - 1)
print("归并排序后的数组A:", A)
冒泡排序
经典的冒泡排序算法
BUBBLESORT(A)
输入:一个包含n个元素的数组A
输出:按非降序排列的数组A(从小到大排序)
for i = 1 to A.length - 1 // 外层循环:遍历数组中的每一个元素(除了最后一个)
for j = A.length downto i + 1 // 内层循环:从数组末尾向前遍历,直到已排序的部分
if A[j] < A[j-1] // 如果当前元素A[j]小于前一个元素A[j-1]
exchange A[j] with A[j-1] // 交换这两个元素的位置,把较小的元素A[j]冒泡到前面
// 注:在每次外层循环结束后,最大的元素会“冒泡”到已排序部分的末尾
def bubble_sort(A):
n = len(A)
for i in range(n - 1): # 外层循环
for j in range(n - 1, i, -1): # 内层循环
if A[j] < A[j - 1]:
A[j], A[j - 1] = A[j - 1], A[j] # 交换元素位置
# 示例使用:
if __name__ == "__main__":
arr = [64, 34, 25, 12, 22, 11, 90]
print("原始数组:", arr)
bubble_sort(arr)
print("排序后的数组:", arr)
最大子数组问题
分治法解决最大子数组问题
FIND-MAX-CROSSING-SUBARRAY(A, low, mid, high)
输入:一个包含n个元素的数组A,以及数组A的下标范围low、mid和high
输出:一个三元组,包含最大子数组的左边界、右边界和和值
left-sum = -inf // 左半部分的和的初始值设为负无穷
sum = 0 // 临时变量,用于计算左半部分的和
for i = mid downto low // 从中间位置mid向左遍历数组A
sum = sum + A[i] // 累加当前元素到sum中
if sum > left-sum // 如果当前左半部分的和大于之前记录的最大和
left-sum = sum // 更新左半部分的最大和
max-left = i // 更新左边界为当前位置i
right-sum = -inf // 右半部分的和的初始值设为负无穷
sum = 0 // 临时变量,用于计算右半部分的和
for j = mid + 1 to high // 从中间位置mid的下一个位置向右遍历数组A
sum = sum + A[j] // 累加当前元素到sum中
if sum > right-sum // 如果当前右半部分的和大于之前记录的最大和
right-sum = sum // 更新右半部分的最大和
max-right = j // 更新右边界为当前位置j
return (max-left, max-right, left-sum + right-sum) // 返回包含最大子数组的左右边界和和值的三元组
FIND-MAXIMUM-SUBARRAY(A, low, high)
输入:一个包含n个元素的数组A,以及数组A的下标范围low和high
输出:一个三元组,包含最大子数组的左边界、右边界和和值
if high == low
return (low, high, A[low]) // 基本情况:只有一个元素,返回当前元素及其位置
mid = [(low + high) / 2] // 计算数组A的中间位置mid
// 递归求解左半部分、右半部分和跨越中点的最大子数组
(left-low, left-high, left-sum) = FIND-MAXIMUM-SUBARRAY(A, low, mid)
(right-low, right-high, right-sum) = FIND-MAXIMUM-SUBARRAY(A, mid + 1, high)
(cross-low, cross-high, cross-sum) = FIND-MAX-CROSSING-SUBARRAY(A, low, mid, high)
// 比较左半部分、右半部分和跨越中点的最大子数组的和值,返回和值最大的那个子数组
if left-sum >= right-sum and left-sum >= cross-sum
return (left-low, left-high, left-sum)
elseif right-sum >= left-sum and right-sum >= cross-sum
return (right-low, right-high, right-sum)
else
return (cross-low, cross-high, cross-sum)
def find_max_crossing_subarray(A, low, mid, high):
left_sum = float("-inf") # 左半部分的和的初始值设为负无穷
sum = 0 # 临时变量,用于计算左半部分的和
max_left = 0 # 初始化左边界为0
# 从中间位置mid向左遍历数组A
for i in range(mid, low - 1, -1):
sum += A[i] # 累加当前元素到sum中
if sum > left_sum: # 如果当前左半部分的和大于之前记录的最大和
left_sum = sum # 更新左半部分的最大和
max_left = i # 更新左边界为当前位置i
right_sum = float("-inf") # 右半部分的和的初始值设为负无穷
sum = 0 # 临时变量,用于计算右半部分的和
max_right = 0 # 初始化右边界为0
# 从中间位置mid的下一个位置向右遍历数组A
for j in range(mid + 1, high + 1):
sum += A[j] # 累加当前元素到sum中
if sum > right_sum: # 如果当前右半部分的和大于之前记录的最大和
right_sum = sum # 更新右半部分的最大和
max_right = j # 更新右边界为当前位置j
return (max_left, max_right, left_sum + right_sum) # 返回包含最大子数组的左右边界和和值的三元组
def find_maximum_subarray(A, low, high):
if high == low:
return (low, high, A[low]) # 基本情况:只有一个元素,返回当前元素及其位置
mid = (low + high) // 2 # 计算数组A的中间位置mid
# 递归求解左半部分、右半部分和跨越中点的最大子数组
(left_low, left_high, left_sum) = find_maximum_subarray(A, low, mid)
(right_low, right_high, right_sum) = find_maximum_subarray(A, mid + 1, high)
(cross_low, cross_high, cross_sum) = find_max_crossing_subarray(A, low, mid, high)
# 比较左半部分、右半部分和跨越中点的最大子数组的和值,返回和值最大的那个子数组
if left_sum >= right_sum and left_sum >= cross_sum:
return (left_low, left_high, left_sum)
elif right_sum >= left_sum and right_sum >= cross_sum:
return (right_low, right_high, right_sum)
else:
return (cross_low, cross_high, cross_sum)
# 示例使用:
if __name__ == "__main__":
arr = [-2, 5, -3, 7, 10, -2, 4, -7, 8, -1, 3, -6, 4, -9, 6, 2, -4, 1, -3, 5]
low, high, max_sum = find_maximum_subarray(arr, 0, len(arr) - 1)
max_subarray = arr[low:high + 1]
print("最大子数组:", max_subarray)
print("最大子数组的和:", max_sum)
矩阵乘法的Strassen算法
矩阵乘法
SQUARE-MATRIX-MULTIPLY(A, B)
输入:两个n×n的方阵A和B
输出:一个新的n×n的方阵C,表示A和B的乘积
n = A.rows // 矩阵A的行数(也是列数,因为A是方阵)
let C be a new n×n matrix // 创建一个新的n×n的矩阵C,用于存储乘积结果
for i = 1 to n // 遍历A的每一行
for j = 1 to n // 遍历B的每一列
c_ij = 0 // 初始化矩阵C的元素c_ij为0,表示乘积结果的当前元素
for k = 1 to n // 遍历矩阵A和B的相应元素
c_ij = c_ij + a_ik * b_kj // 累加A的第i行和B的第j列对应元素的乘积到c_ij
return C // 返回矩阵C,即A和B的乘积结果
import numpy as np
def square_matrix_multiply(A, B):
n = A.shape[0] # 矩阵A的行数(也是列数,因为A是方阵)
C = np.zeros((n, n)) # 创建一个新的n×n的矩阵C,用于存储乘积结果
for i in range(n): # 遍历A的每一行
for j in range(n): # 遍历B的每一列
c_ij = 0 # 初始化矩阵C的元素c_ij为0,表示乘积结果的当前元素
for k in range(n): # 遍历矩阵A和B的相应元素
c_ij += A[i][k] * B[k][j] # 累加A的第i行和B的第j列对应元素的乘积到c_ij
C[i][j] = c_ij # 将计算结果赋给矩阵C的对应元素
return C # 返回矩阵C,即A和B的乘积结果
# 示例使用:
if __name__ == "__main__":
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
result = square_matrix_multiply(A, B)
print("矩阵A:")
print(A)
print("矩阵B:")
print(B)
print("矩阵C(A和B的乘积结果):")
print(result)
递归分治法来实现矩阵乘法
SQUARE-MATRIX-MULTIPLY-RECURSIVE(A, B)
输入:两个n×n的方阵A和B
输出:一个新的n×n的方阵C,表示A和B的乘积
n = A.rows // 矩阵A的行数(也是列数,因为A是方阵)
let C be a new n×n matrix // 创建一个新的n×n的矩阵C,用于存储乘积结果
if n == 1 // 如果矩阵A和B都是1×1的矩阵
c_11 = a_11 * b_11 // 直接计算乘积结果
else // 如果矩阵A和B的维度大于1×1,使用递归分治法
// 将矩阵A和B分成四个块,并按照公式(4.9)分别计算C的四个块
C_11 = SQUARE-MATRIX-MULTIPLY-RECURSIVE(A_11, B_11) + SQUARE-MATRIX-MULTIPLY-RECURSIVE(A_12, B_21)
C_12 = SQUARE-MATRIX-MULTIPLY-RECURSIVE(A_11, B_12) + SQUARE-MATRIX-MULTIPLY-RECURSIVE(A_12, B_22)
C_21 = SQUARE-MATRIX-MULTIPLY-RECURSIVE(A_21, B_11) + SQUARE-MATRIX-MULTIPLY-RECURSIVE(A_22, B_21)
C_22 = SQUARE-MATRIX-MULTIPLY-RECURSIVE(A_21, B_12) + SQUARE-MATRIX-MULTIPLY-RECURSIVE(A_22, B_22)
return C // 返回矩阵C,即A和B的乘积结果
import numpy as np
def square_matrix_multiply_recursive(A, B):
n = A.shape[0] # 矩阵A的行数(也是列数,因为A是方阵)
C = np.zeros((n, n)) # 创建一个新的n×n的矩阵C,用于存储乘积结果
if n == 1: # 如果矩阵A和B都是1×1的矩阵
C[0][0] = A[0][0] * B[0][0] # 直接计算乘积结果
else:
# 将矩阵A和B分成四个块,并按照公式计算C的四个块
A_11 = A[:n // 2, :n // 2]
A_12 = A[:n // 2, n // 2:]
A_21 = A[n // 2:, :n // 2]
A_22 = A[n // 2:, n // 2:]
B_11 = B[:n // 2, :n // 2]
B_12 = B[:n // 2, n // 2:]
B_21 = B[n // 2:, :n // 2]
B_22 = B[n // 2:, n // 2:]
C_11 = square_matrix_multiply_recursive(A_11, B_11) + square_matrix_multiply_recursive(A_12, B_21)
C_12 = square_matrix_multiply_recursive(A_11, B_12) + square_matrix_multiply_recursive(A_12, B_22)
C_21 = square_matrix_multiply_recursive(A_21, B_11) + square_matrix_multiply_recursive(A_22, B_21)
C_22 = square_matrix_multiply_recursive(A_21, B_12) + square_matrix_multiply_recursive(A_22, B_22)
# 将计算结果填充到矩阵C中
C[:n // 2, :n // 2] = C_11
C[:n // 2, n // 2:] = C_12
C[n // 2:, :n // 2] = C_21
C[n // 2:, n // 2:] = C_22
return C # 返回矩阵C,即A和B的乘积结果
# 示例使用:
if __name__ == "__main__":
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
result = square_matrix_multiply_recursive(A, B)
print("矩阵A:")
print(A)
print("矩阵B:")
print(B)
print("矩阵C(A和B的乘积结果):")
print(result)
雇佣问题
雇佣助理
HIRE-ASSISTANT(n)
输入:n个应聘者,编号为0到n
输出:被雇佣的助理编号
best = 0 // 最佳候选人编号初始化为0,即第一个候选人
for i = 1 to n // 遍历所有候选人
interview candidate i // 面试候选人i
// 如果候选人i比当前最佳候选人更优秀
if candidate i is better than candidate best
best = i // 更新最佳候选人编号为i
// 雇佣候选人i(在实际应用中可能有相关的雇佣流程)
hire candidate i
return best // 返回被雇佣的助理的编号
import random
def hire_assistant(n):
best = 0 # 最佳候选人编号初始化为0,即第一个候选人
for i in range(1, n + 1): # 遍历所有候选人
candidate = i # 当前候选人编号
interview_candidate(candidate) # 面试候选人i
# 如果候选人i比当前最佳候选人更优秀
if candidate_is_better(candidate, best):
best = candidate # 更新最佳候选人编号为i
hire_candidate(candidate) # 雇佣候选人i(在实际应用中可能有相关的雇佣流程)
return best # 返回被雇佣的助理的编号
# 示例使用:
def interview_candidate(candidate):
print(f"面试候选人 {candidate}...") # 在实际应用中可以进行面试过程
def candidate_is_better(candidate, best):
return random.random() > 0.5 # 在示例中随机模拟比较候选人优劣
def hire_candidate(candidate):
print(f"雇佣候选人 {candidate}...") # 在实际应用中进行雇佣操作
if __name__ == "__main__":
n = 5 # 假设有5个候选人
hired_assistant = hire_assistant(n)
print(f"被雇佣的助理编号:{hired_assistant}")
随机化雇佣助理算法
RANDOMIZED-HIRE-ASSISTANT(n)
输入:n个应聘者,编号为0到n
输出:被雇佣的助理编号
randomly permute the list of candidate // 随机排列候选人列表
best = 0 // 最佳候选人编号初始化为0,即第一个候选人
for i = 1 to n // 遍历所有候选人
interview candidate i // 面试候选人i
// 如果候选人i比当前最佳候选人更优秀
if candidate i is better than candidate best
best = i // 更新最佳候选人编号为i
// 雇佣候选人i(在实际应用中可能有相关的雇佣流程)
hire candidate i
return best // 返回被雇佣的助理的编号
import random
def randomized_hire_assistant(n):
candidates = list(range(n)) # 候选人列表,编号从0到n-1
random.shuffle(candidates) # 随机排列候选人列表
best = 0 # 最佳候选人编号初始化为0,即第一个候选人
for i in range(1, n + 1): # 遍历所有候选人
candidate = candidates[i - 1] # 当前候选人编号
interview_candidate(candidate) # 面试候选人i
# 如果候选人i比当前最佳候选人更优秀
if candidate_is_better(candidate, best):
best = candidate # 更新最佳候选人编号为i
hire_candidate(candidate) # 雇佣候选人i(在实际应用中可能有相关的雇佣流程)
return best # 返回被雇佣的助理的编号
# 示例使用:
def interview_candidate(candidate):
print(f"面试候选人 {candidate}...") # 在实际应用中可以进行面试过程
def candidate_is_better(candidate, best):
return random.random() > 0.5 # 在示例中随机模拟比较候选人优劣
def hire_candidate(candidate):
print(f"雇佣候选人 {candidate}...") # 在实际应用中进行雇佣操作
if __name__ == "__main__":
n = 5 # 假设有5个候选人
hired_assistant = randomized_hire_assistant(n)
print(f"被雇佣的助理编号:{hired_assistant}")
解决在线雇佣问题
ON-LINE-MAXIMUM(k, n)
输入:整数 k 表示前 k 个候选人将直接被观察,整数 n 表示候选人总数
输出:返回选择的最佳候选人的位置
bestscore = - inf // 初始化最佳候选人的分数为负无穷大
for i = 1 to k // 遍历前 k 个候选人
if score(i) > bestscore // 如果当前候选人的分数大于最佳候选人的分数
bestscore = score(i) // 更新最佳候选人的分数为当前候选人的分数
for i = k+1 to n // 继续遍历剩余的候选人,从第 k+1 个开始
if score(i) > bestscore // 如果当前候选人的分数大于最佳候选人的分数
return i // 返回当前候选人的位置,表示找到了更优秀的候选人
return n // 如果没有更优秀的候选人出现,则返回 n,表示选择最后一个候选人
import random
def score(i):
# 假设这是候选人 i 的分数计算函数
return random.randint(1, 100) # 这里随机生成一个候选人的分数作为示例
def online_maximum(k, n):
bestscore = float('-inf') # 初始化最佳候选人的分数为负无穷大
for i in range(1, k + 1): # 遍历前 k 个候选人
s = score(i)
if s > bestscore: # 如果当前候选人的分数大于最佳候选人的分数
bestscore = s # 更新最佳候选人的分数为当前候选人的分数
for i in range(k + 1, n + 1): # 继续遍历剩余的候选人,从第 k+1 个开始
s = score(i)
if s > bestscore: # 如果当前候选人的分数大于最佳候选人的分数
return i # 返回当前候选人的位置,表示找到了更优秀的候选人
return n # 如果没有更优秀的候选人出现,则返回 n,表示选择最后一个候选人
# 示例使用:
if __name__ == "__main__":
k = 5 # 前 k 个候选人将直接被观察
n = 10 # 候选人总数
best_candidate = online_maximum(k, n)
print("选择的最佳候选人位置:", best_candidate)
随机排列数组
通过排序实现数组元素随机排列
PERMUTE-BY-SORTING(A)
输入:一个包含n个元素的数组A
输出:一个随机排列后的数组A
n = A.length // 获取数组A的长度n
let P[1..n] be a new array // 创建一个新的数组P,用于存储随机排序键
for i = 1 to n // 遍历数组A的每个元素
P[i] = RANDOM(1, n^3) // 为数组P的第i个元素赋一个在范围[1, n^3]内的随机数作为排序键
sort A, using P as sort keys // 使用数组P作为排序键对数组A进行排序
import random
def permute_by_sorting(A):
n = len(A) # 获取数组A的长度n
P = [random.randint(1, n**3) for _ in range(n)] # 生成长度为n的随机排序键数组P
# 使用数组P作为排序键对数组A进行排序
A = [x for _, x in sorted(zip(P, A))]
return A # 返回随机排列后的数组A
# 示例使用:
if __name__ == "__main__":
A = [1, 2, 3, 4, 5]
print("原始数组A:", A)
permuted_A = permute_by_sorting(A)
print("随机排列后的数组A:", permuted_A)
原地随机排列数组元素
RANDOMIZE-IN-PLACE(A)
输入:一个包含n个元素的数组A
输出:原地随机排列后的数组A
n = A.length // 获取数组A的长度n
for i = 1 to n // 遍历数组A的每个元素
swap A[i] with A[Random(i, n)] // 将第i个元素与从i到n之间的随机位置的元素进行交换
import random
def randomize_in_place(A):
n = len(A) # 获取数组A的长度n
for i in range(n): # 遍历数组A的每个元素
rand_index = random.randint(i, n - 1) # 生成从i到n之间的随机位置
A[i], A[rand_index] = A[rand_index], A[i] # 将第i个元素与随机位置的元素进行交换
return A # 返回原地随机排列后的数组A
# 示例使用:
if __name__ == "__main__":
A = [1, 2, 3, 4, 5]
print("原始数组A:", A)
randomize_in_place(A)
print("原地随机排列后的数组A:", A)
对数组元素进行原地随机排列
PERMUTE-WITHOUT-IDENTITY(A)
输入:一个包含n个元素的数组A
输出:原地随机排列后的数组A
n = A.length // 获取数组A的长度n
for i = 1 to n-1 // 遍历数组A的前n-1个元素
swap A[i] with A[RANDOM(i+1, n)] // 将当前元素A[i]与从i+1到n之间的随机位置的元素进行交换
import random
def permute_without_identity(A):
n = len(A) # 获取数组A的长度n
for i in range(n - 1): # 遍历数组A的前n-1个元素
rand_index = random.randint(i + 1, n - 1) # 生成从i+1到n之间的随机位置
A[i], A[rand_index] = A[rand_index], A[i] # 将当前元素A[i]与随机位置的元素进行交换
return A # 返回原地随机排列后的数组A
# 示例使用:
if __name__ == "__main__":
A = [1, 2, 3, 4, 5]
print("原始数组A:", A)
permute_without_identity(A)
print("原地随机排列后的数组A:", A)
对数组元素进行原地完全随机排列
PERMUTE-WITH-ALL(A)
输入:一个包含n个元素的数组A
输出:原地完全随机排列后的数组A
n = A.length // 获取数组A的长度n
for i = 1 to n // 遍历数组A的每个元素
swap A[i] with A[RANDOM(1, n)] // 将当前元素A[i]与数组中的随机位置的元素进行交换
import random
def permute_with_all(A):
n = len(A) # 获取数组A的长度n
for i in range(n): # 遍历数组A的每个元素
rand_index = random.randint(0, n - 1) # 生成从0到n-1之间的随机位置
A[i], A[rand_index] = A[rand_index], A[i] # 将当前元素A[i]与随机位置的元素进行交换
return A # 返回原地完全随机排列后的数组A
# 示例使用:
if __name__ == "__main__":
A = [1, 2, 3, 4, 5]
print("原始数组A:", A)
permute_with_all(A)
print("原地完全随机排列后的数组A:", A)
对数组元素进行循环置换
PERMUTE-BY-CYCLIC(A)
输入:一个包含n个元素的数组A
输出:循环置换后得到的新数组B
n = A.length // 获取数组A的长度n
let B[1..n] be a new array // 创建一个新的数组B,用于存储循环置换后的结果
offset = RANDOM(1, n) // 生成一个在闭区间[1, n]内的随机整数,作为循环右移的偏移量
for i = 1 to n // 遍历数组A的每个元素
dest = i + offset // 计算当前元素的目标位置,即循环右移后的位置
if dest > n // 如果目标位置超过了数组长度,需要进行循环调整
dest = dest - n // 将目标位置调整到合法范围内
B[dest] = A[i] // 将元素A[i]放入数组B的目标位置
return B // 返回循环置换后得到的新数组B
import random
def permute_by_cyclic(A):
n = len(A) # 获取数组A的长度n
B = [0] * n # 创建一个新数组B,用于存储循环置换后的结果
offset = random.randint(1, n) # 生成一个在闭区间[1, n]内的随机整数,作为循环右移的偏移量
for i in range(n): # 遍历数组A的每个元素
dest = (i + offset) % n # 计算当前元素的目标位置,即循环右移后的位置
B[dest] = A[i] # 将元素A[i]放入数组B的目标位置
return B # 返回循环置换后得到的新数组B
# 示例使用:
if __name__ == "__main__":
A = [1, 2, 3, 4, 5]
print("原始数组A:", A)
B = permute_by_cyclic(A)
print("循环置换后得到的新数组B:", B)
数集合 [1, 2, 3, ..., n]
中随机抽取 m
个不重复元素
RANDOM-SAMPLE(m, n)
输入:要抽取的样本大小 m 和整数集合的范围 n
输出:一个包含 m 个不重复元素的随机抽样样本 S
if m == 0
return 空集 // 如果需要抽取的样本大小为0,则返回空集
else
S = RANDOM-SAMPLE(m-1, n-1) // 递归地从 [1, 2, ..., n-1] 中抽取 m-1 个元素作为样本
i = RANDOM(1, n) // 从整数集合中随机选择一个元素 i
if i 属于 S // 检查元素 i 是否已经在样本中,防止重复选择
S = S 并 {n} // 如果 i 已在样本中,将 n 加入样本中
else
S = S 并 {i} // 如果 i 不在样本中,将 i 加入样本中
return S // 返回最终抽样样本 S
import random
def random_sample(m, n):
if m == 0:
return set() # 如果需要抽取的样本大小为0,则返回空集
else:
S = random_sample(m - 1, n - 1) # 递归地从 [1, 2, ..., n-1] 中抽取 m-1 个元素作为样本
i = random.randint(1, n) # 从整数集合中随机选择一个元素 i
if i in S: # 检查元素 i 是否已经在样本中,防止重复选择
S.add(n) # 如果 i 已在样本中,将 n 加入样本中
else:
S.add(i) # 如果 i 不在样本中,将 i 加入样本中
return S # 返回最终抽样样本 S
# 示例使用:
if __name__ == "__main__":
m = 5 # 抽取样本大小为5
n = 10 # 整数集合范围为[1, 2, ..., 10]
sample = random_sample(m, n)
print("随机抽样样本:", sample)