zoukankan      html  css  js  c++  java
  • Knuth-Shuffle:一个公平的洗牌算法

    问题介绍

    洗牌,简单来说就是随机交换牌的位置,但是如何才是公平的呢,洗牌的结果是所有元素的一个排列。一副牌如果有 n 个元素,最终排列的可能性一共有 n! 个。公平的洗牌算法,应该能等概率地给出这 n! 个结果中的任意一个。这样的暴力解法时间复杂度为O(n!),不可取。公平是说,对于每一个排列,每一个元素都能等概率的出现在每一个位置,也可以反过来,每一个位置都能等概率的放置每一个元素。基于此,我们可以设计出下面的算法。

    算法实现

    import java.util.Arrays;
    
    public class KnuthShuffle {
    
      /**
       * 洗牌
       */
      public void shuffle(int[] nums) {
        for (int i = nums.length - 1; i >= 0; i--) {
          swap(nums, i, (int) (Math.random() * (i + 1)));
        }
      }
    
      private void swap(int[] nums, int left, int right) {
        int temp = nums[left];
        nums[left] = nums[right];
        nums[right] = temp;
      }
    
      public static void main(String[] args) {
        int[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        new KnuthShuffle().shuffle(nums);
        System.out.println(Arrays.toString(nums));
      }
    
    }
    

    上面的算法就是大名鼎鼎的Knuth 洗牌算法。

    第一次循环从1,2,3,4,5之间随机选出一个数,假设选出为2,和最后的5交换,任意一个元素出现在最后一个位置的概率都是1/5,

    第二次循环从1,5,3,4之间随机选出一个数,假设为3,和最后的4交换,3没有满足第一次循环的概率是4/5,满足这一次循环的概率是1/4,最终为4/5*1/4=1/5。
    以此类推,每一个位置放置每一个元素的概率都是1/5。
    java中Collections.shuffle()就是使用的这种算法。

    参考

    【算法杂谈4】神一样的随机算法

  • 相关阅读:
    ReentrantLock和AQS
    CAS
    java8中ConcurrentHashMap
    java8中的HashMap
    TCP和UDP
    慢查询日志和profiling
    explain的使用
    select、poll、epoll之间的区别
    I/O模型
    生产者-消费者模式
  • 原文地址:https://www.cnblogs.com/strongmore/p/14489683.html
Copyright © 2011-2022 走看看