📜  产生1到N的随机排列(1)

📅  最后修改于: 2023-12-03 15:06:23.550000             🧑  作者: Mango

产生1到N的随机排列

对于程序员来说,生成1到N的随机排列是一个常见的需求。具体来说,需要生成一个包含1到N的所有数的排列,并且这个排列是随机的,每个数字出现的位置也是随机的。本文将为你介绍几种常见的实现方法。

Fisher–Yates 洗牌算法

Fisher–Yates 洗牌算法,也称作 Knuth shuffle,是生成随机排列的经典算法,其流程如下:

  1. 将1到N的所有数字放入一个数组中。
  2. 从数组的最后一个元素开始,随机选取一个位置并将该位置的元素与最后一个元素交换。
  3. 然后从倒数第二个元素开始,随机选取一个位置并将该位置的元素与倒数第二个元素交换。
  4. 重复上述过程,直到第一个元素。

最终得到的数组就是一个随机排列。

下面是Python代码实现:

import random

def shuffle(lst):
    for i in range(len(lst)-1, 0, -1):
        j = random.randint(0, i)
        lst[i], lst[j] = lst[j], lst[i]
    return lst

n = 5
lst = list(range(1, n+1))
print(shuffle(lst))

在这个实现中,我们使用了Python的随机模块random,其中randint函数返回一个在指定范围内的整数。这种实现方法时间复杂度为O(N),空间复杂度为O(1),是一种性能不错的实现。

快速排序算法

除了Fisher–Yates 洗牌算法以外,我们还可以利用快速排序算法的原理生成随机排列。具体来说,我们按照快速排序的方式划分元素,只不过每次划分时,我们随机选取一个数作为pivot,这样就得到了随机排列。这个实现方法的Python代码如下:

import random

def quicksort(lst, start, end):
    if start < end:
        pivot_idx = random.randint(start, end)
        pivot_val = lst[pivot_idx]
        lst[pivot_idx], lst[end] = lst[end], lst[pivot_idx]
        left, right = start, end-1

        while left <= right:
            while left <= right and lst[left] <= pivot_val:
                left += 1
            while left <= right and lst[right] >= pivot_val:
                right -= 1
            if left <= right:
                lst[left], lst[right] = lst[right], lst[left]
                left += 1
                right -= 1

        lst[end], lst[left] = lst[left], lst[end]
        quicksort(lst, start, left-1)
        quicksort(lst, left+1, end)

def shuffle(lst):
    quicksort(lst, 0, len(lst)-1)
    return lst

n = 5
lst = list(range(1, n+1))
print(shuffle(lst))

这种实现方法的时间复杂度为O(NlogN),空间复杂度为O(logN)。相比于Fisher–Yates 洗牌算法而言,可能性能会略差一些。不过我们可以发现,这种实现方法是基于快排实现的,因此在一些情况下比Fisher–Yates 洗牌算法更加灵活。

总结

我们介绍了两种生成1到N的随机排列的算法——Fisher–Yates 洗牌算法和基于快排的算法。无论选择哪种算法,我们都需要注意随机数的生成过程,以保证随机排列是真正随机的。