音乐随机播放算法,安排!!!

作者: android框架安卓 | 来源:发表于2018-07-29 20:28 被阅读69次

    常见的音乐随机播放算法主要有两种:一是Shuffle算法;二是Random算法。

    一 Shuffle算法

    Shuffle算法和排序算法正好相反,是从有序到乱序的一个过程,俗称洗牌算法。它将播放列表中的歌曲顺序打乱,变成一个和原来歌曲顺序没有任何关系的乱序的播放列表,之后进行歌曲的播放,并支持当用户点击“上一首”时,能够回到刚刚播放的那一首歌曲。

    二 Random算法

    Random算法是在选取即将播放的歌曲时,进行一个随机数的运算,得到即将播放的歌曲在播放列表中的索引,播放列表本身并没有被打乱,只是利用随机函数从播放列表中选取一首歌曲进行播放而已。

    现在比较普遍的随机数生成算法是基于线性同余算法实现的,例如C语言标准库函数rand()就是利用它产生随机数的。线性同余算法能够产生均匀分布的随机数,但是它依赖于给定的随机数的上限,如果上限越小,产生的随机数重复的概率就越大。

    Random算法另一个缺陷是当点击“上一首”时,跟“下一首”功能完全一样,都是重新生成随机数,并利用它从播放列表中选取歌曲进行播放,而不会回到刚刚播放的那一首歌。当然,这个缺陷可以通过提供历史记录来弥补,只是需要花费额外的空间。

    三 随机函数

    上面两种算法的关键都是随机函数,下面介绍Java和C两种语言中随机函数的使用。

    3.1)Java中的随机函数

    Java是采用线性同余算法产生随机数的,优点是随机性好,周期长,速度快,易于计算机软件实现,缺点是产生的随机数受数学规律的制约,具有周期性和相关性,只能产生伪随机序列。JDK提供的随机数生成方式有两种:

    3.1.1)Math.random()函数

    该函数返回0到1区间中的某个double值,源码实现如下:

    privatestaticRandom randomNumberGenerator;

    privatestaticsynchronizedRandominitRNG(){

            Random rnd = randomNumberGenerator;

    return(rnd ==null) ? (randomNumberGenerator =newRandom()) : rnd;

    }

    publicstaticdoublerandom(){

            Random rnd = randomNumberGenerator;

    if(rnd ==null) rnd = initRNG();

    returnrnd.nextDouble();

        }

    可见,该函数底层是调用Random类实现的,首次调用random函数时,静态成员变量randomNumberGenerator为空,因此将调用Random类的构造函数进行初始化,随后每次调用random函数randomNumberGenerator不再为空,将不会再实例化Random类,因此,每次调用Math.random()函数用到的都是同一个种子,也就是首次调用的系统时间产生的种子。

    3.1.2)Random类

    位于Java.util包中,该类有两个构造函数,实现如下:

    publicRandom(){

    this(seedUniquifier() ^ System.nanoTime());

    }

    publicRandom(longseed){

    this.seed =newAtomicLong(initialScramble(seed));

        }

    可见,构造函数默认使用当前的系统时间产生种子,用于初始化Random对象。之后就可以调用各种next*函数来获取各种类型的随机数,如nextBytes,nextInt,nextDouble,nextGaussian等等。

    3.2)C/C++中的随机函数

    C/C++中最常用的生成伪随机数的方法是C标准库提供的rand()函数,它定义在stdlib.h文件中,能够返回0~RAND_MAX之间均匀分布的伪随机数(RAND_MAX至少为32767,一般默认为32767)。

    直接调用rand(),每次生成的伪随机序列是相同的,因为rand()在生成随机数时会使用一个种子(默认值是1),作为计算随机数的初始值,如果种子相同,那么生成的伪随机序列也将是一样的。解决的办法很简单,就是每次使用不同的种子来调用rand()函数,srand()函数就是用来设置rand()函数产生随机数时使用的种子的。

    srand()函数原型如下:

    voidsrand(

    unsignedintseed

    );

    srand()和rand()配合使用的示例如下:

    #include

    #include

    #include

    intmain(void)

    {

    inti;

    /* Seed the random-number generator with current time so that

        * the numbers will be different every time we run.

        */

    srand( (unsigned)time(NULL) );

    /* Display 10 numbers. */

    for( i =0;  i <10;i++ )

    printf("  %6d\n", rand() );

    }

    需要注意的一点是,上面代码在生成多个随机数时,要将srand()放到for循环的外面,否则上面输出的10个随机数都将是一样的,因为计算机运行速度太快,导致time()函数执行的结果没来得及改变。详见下图。

    四 音乐随机播放算法的Shuffle实现

    4.1)C/C++版本

    #include 

    #include 

    usingnamespacestd;

    //得到范围start~end之间的随机数

    intrand(intstart,intend)

    returnrand()%(end - start) + start;

    voidswap(int* a,int* b)

        *a = *a ^ *b; 

        *b = *a ^ *b; 

        *a = *a ^ *b; 

    voidshuffle(inta[],intlen)

    intkey;

    srand((unsignedint)time(NULL));//srand应该放在for循环之外

    for(inti =0; i< len; i++)

        { 

    key = rand(0, len);

    printf("key = %d\n", key);

    swap(a[i], a[key]);//乱序

        } 

    intmain(intargc,char*argv[])

    inta[8]={3,5,7,2,12,1,8,6};

    shuffle(a,8);

    for(inti =0; i <8; i++)

        { 

    printf("%d\n", a[i]);

        } 

    system("pause");

    return0;

    }

    4.2)Java版本

    importjava.util.Random;

    publicclassASCE{

    publicstaticvoidmain(String arg[]){

    String[] musicUrl = {"/music/1.mp3","/music/2.mp3","/music/3.mp3",

    "/music/4.mp3","/music/5.mp3","/music/6.mp3","/music/7.mp3",

    "/music/8.mp3","/music/9.mp3","/music/10.mp3"};

    shuffle(musicUrl);

    for(String music : musicUrl) {

    System.out.println(music);

    }

    }

    publicstaticvoidshuffle(String[] musicUrl){

    intkey;

    String temp;

    Random rand =newRandom();

    for(inti =0; i < musicUrl.length; i++) {

    key = rand.nextInt(musicUrl.length -1);

    temp = musicUrl[i];

    musicUrl[i] = musicUrl[key];

    musicUrl[key] = temp;

    }

    }

    }

    五 现成的Shuffle库算法

    其实无论在C++还是Java中,都已经实现了Shuffle算法,在实际项目开发中,如果不是有特殊要求的话,完全没有必要自己去实现Shuffle算法,下面就来看看已有的Shuffle算法。

    5.1)C++中的Shuffle算法

    C++ STL中的函数random_shuffle()就是用来对一个元素序列进行随机重新排序的算法,函数原型如下:

    template

    voidrandom_shuffle(

    RandomAccessIterator_First, //指向序列首元素的迭代器

    RandomAccessIterator_Last//指向序列最后一个元素的下一个位置的迭代器

      );

    template

    voidrandom_shuffle(

    RandomAccessIterator_First,

    RandomAccessIterator_Last,

    RandomNumberGenerator& _Rand//调用随机数产生器的函数

      );

    具体用法可参见:http://blog.csdn.net/ACE1985/article/details/5868682 。

    5.2)Java中的Shuffle算法

    Collections类中实现了Shuffle算法,这个类位于java.util包中,有两个重载函数,下面直接看源码:

    publicstaticvoidshuffle(List list){

            Random rnd = r;

    if(rnd ==null)

    r = rnd =newRandom();

            shuffle(list, rnd);

        }

    privatestaticRandom r;

    publicstaticvoidshuffle(List list, Random rnd){

    intsize = list.size();

    if(size < SHUFFLE_THRESHOLD || listinstanceofRandomAccess) {

    for(inti=size; i>1; i--)

    swap(list, i-1, rnd.nextInt(i));

    }else{

                Object arr[] = list.toArray();

    // Shuffle array

    for(inti=size; i>1; i--)

    swap(arr, i-1, rnd.nextInt(i));

    // Dump array back into list

                ListIterator it = list.listIterator();

    for(inti=0; i

                    it.next();

                    it.set(arr[i]);

                }

            }

        }

    如有什么建议和疑问,欢迎留言讨论。

    欢迎大家加群技术交流:367685933

    相关文章

      网友评论

        本文标题:音乐随机播放算法,安排!!!

        本文链接:https://www.haomeiwen.com/subject/gbkamftx.html