一個關于Android音樂隨機播放的算法

pasd1866 8年前發布 | 6K 次閱讀 算法 Android開發 移動開發

想法

偽隨機。

你的音樂列表里有一些歌,每首歌的初始隨機因數為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.
  • <p/>
  • 適用于音樂隨機播放等
  • GitHub: https://github.com/XunMengWinter
  • <p/>
  • latest edited date: 2016-08-26 *
  • @author ice */ public class RandomPicker {

    private ArrayList<Integer> mOriginWeightList = new ArrayList<>(); private ArrayList<Integer> mCurrentWeightList = new ArrayList<>(); private ArrayList<Integer> 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<Integer> 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;
}

}</code></pre>

每次調用next()的時候,都要做兩次for循環遍歷列表,列表里12首歌倒是毫無壓力,列表要是有500首歌的話肯定會延遲了,此處待改進。

 

來自:http://www.jianshu.com/p/472fed76690a

 

 本文由用戶 pasd1866 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!