Java Alias Method算法实现 Java抽奖功能 算法实现

前言

Alias Method 是一种高效的高效的离散分布采样算法

Alias Method 充分利用概率分布加和为1的性质,通过空间换时间的方法,在常数时间内,完成非均匀到均匀采样的映射。
常用在抽奖算法上

一、Alias Method 代码实现

创建一个AliasMethod类



import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

public class AliasMethod {

    private final Random random;     /* 随机方法 */
    private final int[] alias;     /* 存放填未命中返回的一方 */
    private final double[] probability;     /*存放 新生成的概率*/

    public AliasMethod(List<Double> probabilities) {
        this(probabilities, new Random());
    }
    public AliasMethod(List<Double> probabilities, Random random) {
        /**
         * 校验入参
         */
        if (probabilities == null || random == null) throw new NullPointerException();
        if (probabilities.size() == 0)
            throw new IllegalArgumentException("Probability vector must be nonempty.");
        /* 初始化数组容量*/
        probability = new double[probabilities.size()];
        alias = new int[probabilities.size()];
        this.random = random;
        /*计算概率平均值*/
        final double average = 1.0 / probabilities.size();
        probabilities = new ArrayList<Double>(probabilities);
        /*初始化两个队列 用于接受 大于,小于平均概率的选项*/
        Deque<Integer> small = new ArrayDeque<>();
        Deque<Integer> large = new ArrayDeque<>();
       /*遍历概率项,进行划分*/
        for (int i = 0; i < probabilities.size(); ++i) {
            if (probabilities.get(i) >= average) large.add(i);
            else small.add(i);
        }
        /**
         * 将小于 平均概率得选项乘总选项个数   得到概率 x
         * 将大于 平均值的概率选项 进行相关减除  得到  y
         * 并且y的选项 下标记录到alias集合中
         * 继续判断 y 是否还大于 平均概率 如果大于  继续添加到 队列中进行 上述操作 否则 添加到 小于平均概率的对象中 进行上述操作
         * 逻辑分析
         * 将这两个选项 综合 拼成一个 为 100%的概率
         * 注意: 一个单元中有且之能有两个选项去拼成100%的概率  即 x+y =100%
         */
        while (!small.isEmpty() && !large.isEmpty()) {
           //得到 两个选项的下标
            int less = small.removeLast();
            int more = large.removeLast();
          /*将小于平均概率的数组下标对应的概率 进行增加概率*/
            probability[less] = probabilities.get(less) * probabilities.size();
            /*记录大于平均概率的选项的下标*/
            alias[less] = more;
           /*将大于 平均值的概率选项 进行减除*/
            probabilities.set(more, (probabilities.get(more) + probabilities.get(less)) - average);
          /*继续判断 y 是否还大于 平均概率 如果大于  继续添加到 队列中进行 上述操作 */
            if (probabilities.get(more) >= 1.0 / probabilities.size()) large.add(more);
            /*否则 添加到 小于平均概率的对象中 进行上述操作*/
            else small.add(more);
        }
        /* 补齐空概率的选项下标为 188%*/
        while (!small.isEmpty()) probability[small.removeLast()] = 1.0;
        while (!large.isEmpty()) probability[large.removeLast()] = 1.0;
    }

    public int next() {
        /*
         从 选项中随机得到一个选项
         */
        int column = random.nextInt(probability.length);
        /*判断随机生成的数值是在哪个范围之上*/
        boolean coinToss = random.nextDouble() < probability[column];
        /*
        返回对应的结果
         */
        return coinToss ? column : alias[column];
    }

    public static void main(String[] args) {
        TreeMap<String, Double> map = new TreeMap<String, Double>();
        map.put("1金币", 0.2);
        map.put("2金币", 0.15);
        map.put("3金币", 0.1);
        map.put("4金币", 0.05);
        map.put("未中奖", 0.5);
        List<Double> list = new ArrayList<Double>(map.values());
        List<String> gifts = new ArrayList<String>(map.keySet());
        AliasMethod method = new AliasMethod(list);
        Map<String, AtomicInteger> resultMap = new HashMap<String, AtomicInteger>();
        for (int i = 0; i < 100000; i++) {
            int index = method.next();
            String key = gifts.get(index);
            if (!resultMap.containsKey(key)) {
                resultMap.put(key, new AtomicInteger());
            }
            resultMap.get(key).incrementAndGet();
        }
        for (String key : resultMap.keySet()) {
            System.out.println(key + "==" + resultMap.get(key));
        }
    }

}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 实现数字签名可以使用 Java Cryptography Architecture (JCA) 提供的工具类和算法。下面是一个简单的示例,演示如何使用 Java 实现数字签名: ```java import java.io.File; import java.io.FileInputStream; import java.security.KeyStore; import java.security.PrivateKey; import java.security.Signature; public class DigitalSignatureExample { public static void main(String[] args) throws Exception { // 加载密钥库 String keyStoreFile = "keystore.jks"; String keyStorePassword = "password"; String keyAlias = "alias"; String keyPassword = "password"; KeyStore keyStore = KeyStore.getInstance("JKS"); keyStore.load(new FileInputStream(keyStoreFile), keyStorePassword.toCharArray()); // 获取私钥 PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyAlias, keyPassword.toCharArray()); // 加载待签名文件 String inputFile = "input.pdf"; byte[] inputBytes = new byte[(int) new File(inputFile).length()]; FileInputStream input = new FileInputStream(inputFile); input.read(inputBytes); input.close(); // 使用 SHA-256 算法计算摘要 byte[] digest = MessageDigest.getInstance("SHA-256").digest(inputBytes); // 使用 RSA 算法对摘要进行签名 Signature signature = Signature.getInstance("SHA256withRSA"); signature.initSign(privateKey); signature.update(digest); byte[] signatureBytes = signature.sign(); // 输出签名结果 System.out.println("Digital signature:"); System.out.println(new String(Base64.getEncoder().encode(signatureBytes))); } } ``` 上述代码加载了一个密钥库,获取了一个私钥,并使用该私钥对一个文件进行签名。签名过程包括计算文件的摘要和使用 RSA 算法对摘要进行签名。最终输出签名结果。请注意,此示例仅用于演示目的,实际使用中应该更加完善和安全。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值