一个随机播放的算法

想法:

伪随机。
你的音乐列表里有一些歌,每首歌的初始随机因数为1。
每次你点击下一首时,每首歌的随机因数都会加1,然后随机到的那首歌随机因数变为0。
随机因数越大,被随机到的几率就越高。

比如有4首歌,那么下表是一种可能出现的情况:

- Love Story 东风破 Refrain Tassel
第几次 随机因数 随机因数 随机因数 随机因数 随机到
1 1 1 1 1 东风破
2 2 0 2 2 Love Story
3 0 1 3 3 Refrain
4 1 2 0 4 Tassel
5 2 3 1 0 Love Story
6 0 4 2 1 Tassel
7 1 5 3 0 东风破
8 2 0 4 1 Love Story
9 0 1 5 2 Tassel
10 1 2 6 0 ...

...
可以看到,Refrain 这首歌连续6次没有出现,它的随机因数累加到了6,那么第十次它被随机到的概率是6/(1+2+6),即三分之二。
上面使用的是随机因数累加,其实我们还可以让随机因数累乘等等...

Demo及实现

RandomPicker

Demo中的的大图截图自网易云音乐。
前往GitHub Star/Fork/Compile

如何使用

快速开始:

RandomPicker randomPicker = new RandomPicker(12);
int nextPos = randomPicker.next();

更多方法:

randomPicker.setMultiplyNumber(3);
randomPicker.setAddNumber(2);
randomPicker.setNextPick(5);
randomPicker.add();
randomPicker.changeOriginWeight(0,3);
randomPicker.getHistoryList();

更多更多:
请下载项目查看源码

RandomPicker源码

package top.wefor.randompicker;

import java.util.ArrayList;
import java.util.Random;

/**
 * Created on 16/8/26.
 * 

* 适用于音乐随机播放等 * GitHub: https://github.com/XunMengWinter *

* latest edited date: 2016-08-26 * * @author ice */ public class RandomPicker { private ArrayList mOriginWeightList = new ArrayList<>(); private ArrayList mCurrentWeightList = new ArrayList<>(); private ArrayList mHistoryList = new ArrayList<>(); private int mMultiplyNumber = 1; private int mAddNumber = 1; private int mPickedPosition; private boolean isRepeatable; private Integer mNextPickPosition; Random mRandom = new Random(); public RandomPicker() { //默认一个,避免报错。 new RandomPicker(1); } public RandomPicker(int size) { initSize(size); } /*设置累乘积数*/ public void setMultiplyNumber(int multiplyNumber) { mMultiplyNumber = multiplyNumber; } /*设置累加积数*/ public void setAddNumber(int addNumber) { mAddNumber = addNumber; } /*指定下一次选中的位置*/ public void setNextPick(int pickedPosition) { mNextPickPosition = pickedPosition; } /*是否允许连续两次出现同一个位置*/ public void setRepeatable(boolean repeatable) { isRepeatable = repeatable; } /*初始化列表长度*/ public void initSize(int size) { mOriginWeightList.clear(); mCurrentWeightList.clear(); mHistoryList.clear(); for (int i = 0; i < size; i++) add(); } /*获得当前条目数*/ public int getSize() { return mOriginWeightList.size(); } /*获取历史条目的位置列表*/ public ArrayList getHistoryList() { return mHistoryList; } /*上为配置参数*/ /*下为逻辑实现*/ /*获得下一个随机条目的位置*/ public int next() { random(); mHistoryList.add(mPickedPosition); return mPickedPosition; } public void add() { // 默认每个条目的比重为1. add(getSize(), 1); } /*添加一个条目*/ public void add(int index, int weight) { mOriginWeightList.add(index, weight); mCurrentWeightList.add(index, calculateWeight(0, weight)); } /*修改一个条目的比重*/ public void changeOriginWeight(int index, int weight) { mOriginWeightList.set(index, weight); int currentWeight = mCurrentWeightList.get(index); mCurrentWeightList.set(index, currentWeight / mOriginWeightList.get(index) * weight); } /*移除一个条目*/ public void remove(int index) { mOriginWeightList.remove(index); mCurrentWeightList.remove(index); } /*执行随机算法*/ private void random() { // 算出下一次选中的位置 if (mNextPickPosition != null) { mPickedPosition = mNextPickPosition; mNextPickPosition = null; } else { long allCount = 0; for (int i = 0; i < mCurrentWeightList.size(); i++) { allCount += mCurrentWeightList.get(i); } long randomLong = (long) (mRandom.nextDouble() * allCount); long currentLong = 0; for (int i = 0; i < mCurrentWeightList.size(); i++) { currentLong += mCurrentWeightList.get(i); if (currentLong > randomLong) { mPickedPosition = i; break; } } } // 若列表长度小于2,则下一次位置必为0. if (mCurrentWeightList.size() < 2) { mPickedPosition = 0; return; } // 预先算好下一次的比重 for (int i = 0; i < mCurrentWeightList.size(); i++) { int weight = calculateWeight(mCurrentWeightList.get(i), mOriginWeightList.get(i)); mCurrentWeightList.set(i, weight); } if (isRepeatable) mCurrentWeightList.set(mPickedPosition, calculateWeight(0, mOriginWeightList.get(mPickedPosition))); else mCurrentWeightList.set(mPickedPosition, 0); } /*计算下一次的比重*/ private int calculateWeight(int currentWeight, int originWeight) { return (currentWeight + mAddNumber) * mMultiplyNumber * originWeight; } }

每次调用next()的时候,都要做两次for循环遍历列表,列表里12首歌倒是毫无压力,列表要是有500首歌的话肯定会延迟了,此处待改进。


p.s. 如果你有更好的建议,请留言或者在GitHub fork并提交pull请求。

你可能感兴趣的:(一个随机播放的算法)