【算法学习1】 基础知识接入

参考书籍:算法导论(第三版)

基础知识

插入排序

插入排序算法

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算法

矩阵乘法

image-20230723192639276

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)


递归分治法来实现矩阵乘法

image-20230724083350791

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}")


解决在线雇佣问题

image-20230724120459015

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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星辰之光.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值