赞
踩
之前就一直好奇手机QQ音乐中的随机播放是怎么实现的。随机过程很好实现,主要是上一曲以及下一曲的选择上。今天看博客,恰巧看到了有一篇简单介绍了常见的音乐随机播放算法。下面根据博主ACE1985的介绍再结合自己的一点感受做下总结。
常见的音乐随机播放算法主要有两种:一是Shuffle算法;二是Random算法。
一 Shuffle算法
Shuffle算法和排序算法正好相反,是从有序到乱序的一个过程,俗称洗牌算法。它将播放列表中的歌曲顺序打乱,变成一个和原来歌曲顺序没有任何关系的乱序的播放列表,之后进行歌曲的播放,并支持当用户点击“上一首”时,能够回到刚刚播放的那一首歌曲。
二 Random算法
Random算法是在选取即将播放的歌曲时,进行一个随机数的运算,得到即将播放的歌曲在播放列表中的索引,播放列表本身并没有被打乱,只是利用随机函数从播放列表中选取一首歌曲进行播放而已。
现在比较普遍的随机数生成算法是基于线性同余算法实现的,例如C语言标准库函数rand()就是利用它产生随机数的。线性同余算法能够产生均匀分布的随机数,但是它依赖于给定的随机数的上限,如果上限越小,产生的随机数重复的概率就越大。
Random算法另一个缺陷是当点击“上一首”时,跟“下一首”功能完全一样,都是重新生成随机数,并利用它从播放列表中选取歌曲进行播放,而不会回到刚刚播放的那一首歌。当然,这个缺陷可以通过提供历史记录来弥补,只是需要花费额外的空间。
3.2)C/C++中的随机函数
C/C++中最常用的生成伪随机数的方法是C标准库提供的rand()函数,它定义在stdlib.h文件中,能够返回0~RAND_MAX之间均匀分布的伪随机数(RAND_MAX至少为32767,一般默认为32767)。
直接调用rand(),每次生成的伪随机序列是相同的,因为rand()在生成随机数时会使用一个种子(默认值是1),作为计算随机数的初始值,如果种子相同,那么生成的伪随机序列也将是一样的。解决的办法很简单,就是每次使用不同的种子来调用rand()函数,srand()函数就是用来设置rand()函数产生随机数时使用的种子的。
srand()函数原型如下:
1. void srand(
2. unsigned int seed
3. );
srand()和rand()配合使用的示例如下:
1. #include <stdlib.h>
2. #include <stdio.h>
3. #include <time.h>
4.
5. int main( void )
6. {
7. int i;
8.
9. /* Seed the random-number generator with current time so that
10. * the numbers will be different every time we run.
11. */
12. srand( (unsigned)time( NULL ) );
13.
14. /* Display 10 numbers. */
15. for( i = 0; i < 10;i++ )
16. printf( " %6d\n", rand() );
17.}
需要注意的一点是,上面代码在生成多个随机数时,要将srand()放到for循环的外面,否则上面输出的10个随机数都将是一样的,因为计算机运行速度太快,导致time()函数执行的结果没来得及改变。详见下图。
四 音乐随机播放算法的Shuffle实现
4.1)C/C++版本
1. #include <cstdlib>
2. #include <iostream>
3. using namespace std;
4.
5. //得到范围start~end之间的随机数
6. int rand(int start, int end)
7. {
8. return rand()%(end - start) + start;
9. }
10.
11.void swap(int* a, int* b)
12.{
13. *a = *a ^ *b;
14. *b = *a ^ *b;
15. *a = *a ^ *b;
16.}
17.void shuffle(int a[], int len)
18.{
19. int key;
20. srand((unsigned int)time(NULL));//srand应该放在for循环之外
21. for(int i = 0; i< len; i++)
22. {
23. key = rand(0, len);
24. printf("key = %d\n", key);
25. swap(a[i], a[key]); //乱序
26. }
27.}
28.
29.int main(int argc, char *argv[])
30.{
31. int a[8]={3, 5, 7, 2, 12, 1, 8, 6};
32. shuffle(a, 8);
33. for(int i = 0; i < 8; i++)
34. {
35. printf("%d\n", a[i]);
36. }
37. system("pause");
38. return 0;
39.}
4.2)Java版本
1. import java.util.Random;
2.
3. public class ASCE {
4.
5. public static void main(String arg[]) {
6. String[] musicUrl = { "/music/1.mp3", "/music/2.mp3", "/music/3.mp3",
7. "/music/4.mp3", "/music/5.mp3", "/music/6.mp3", "/music/7.mp3",
8. "/music/8.mp3", "/music/9.mp3", "/music/10.mp3" };
9.
10. shuffle(musicUrl);
11. for (String music : musicUrl) {
12. System.out.println(music);
13. }
14. }
15.
16. public static void shuffle(String[] musicUrl) {
17. int key;
18. String temp;
19. Random rand = new Random();
20.
21. for (int i = 0; i < musicUrl.length; i++) {
22. key = rand.nextInt(musicUrl.length - 1);
23. temp = musicUrl[i];
24. musicUrl[i] = musicUrl[key];
25. musicUrl[key] = temp;
26. }
27. }
28.}
五 现成的Shuffle库算法
其实无论在C++还是Java中,都已经实现了Shuffle算法,在实际项目开发中,如果不是有特殊要求的话,完全没有必要自己去实现Shuffle算法,下面就来看看已有的Shuffle算法。
5.1)C++中的Shuffle算法
C++ STL中的函数random_shuffle()就是用来对一个元素序列进行随机重新排序的算法,函数原型如下:
1. template<class RandomAccessIterator>
2. void random_shuffle(
3. RandomAccessIterator _First, //指向序列首元素的迭代器
4. RandomAccessIterator _Last //指向序列最后一个元素的下一个位置的迭代器
5. );
6. template<class RandomAccessIterator, class RandomNumberGenerator>
7. void random_shuffle(
8. RandomAccessIterator _First,
9. RandomAccessIterator _Last,
10. RandomNumberGenerator& _Rand //调用随机数产生器的函数
11. );
具体用法可参见:http://blog.csdn.net/ACE1985/article/details/5868682 。
5.2)Java中的Shuffle算法
Collections类中实现了Shuffle算法,这个类位于java.util包中,有两个重载函数,下面直接看源码:
1. public static void shuffle(List<?> list) {
2. Random rnd = r;
3. if (rnd == null)
4. r = rnd = new Random();
5. shuffle(list, rnd);
6. }
7. private static Random r;
8.
9. public static void shuffle(List<?> list, Random rnd) {
10. int size = list.size();
11. if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
12. for (int i=size; i>1; i--)
13. swap(list, i-1, rnd.nextInt(i));
14. } else {
15. Object arr[] = list.toArray();
16.
17. // Shuffle array
18. for (int i=size; i>1; i--)
19. swap(arr, i-1, rnd.nextInt(i));
20.
21. // Dump array back into list
22. ListIterator it = list.listIterator();
23. for (int i=0; i<arr.length; i++) {
24. it.next();
25. it.set(arr[i]);
26. }
27. }
28.}
参考文献:
1)http://www.ifanr.com/29498 从随机播放算法看iPod的细节之美
2)http://blog.csdn.net/cstn_kdlx/article/details/7326516 随机数生成问题小结
3)http://blog.csdn.net/hcy0727/article/details/7581671 洗牌算法
4)http://blog.csdn.net/chosen0ne/article/details/6129315 随机播放CD
5)http://blog.csdn.net/ACE1985/article/details/5868682 random_shuffle()和transform算法
转载自http://blog.csdn.net/asce1885/article/details/7582735
之前就一直好奇手机QQ音乐中的随机播放是怎么实现的。随机过程很好实现,主要是上一曲以及下一曲的选择上。今天看博客,恰巧看到了有一篇简单介绍了常见的音乐随机播放算法。下面根据博主ACE1985的介绍再结合自己的一点感受做下总结。
常见的音乐随机播放算法主要有两种:一是Shuffle算法;二是Random算法。
一 Shuffle算法
Shuffle算法和排序算法正好相反,是从有序到乱序的一个过程,俗称洗牌算法。它将播放列表中的歌曲顺序打乱,变成一个和原来歌曲顺序没有任何关系的乱序的播放列表,之后进行歌曲的播放,并支持当用户点击“上一首”时,能够回到刚刚播放的那一首歌曲。
二 Random算法
Random算法是在选取即将播放的歌曲时,进行一个随机数的运算,得到即将播放的歌曲在播放列表中的索引,播放列表本身并没有被打乱,只是利用随机函数从播放列表中选取一首歌曲进行播放而已。
现在比较普遍的随机数生成算法是基于线性同余算法实现的,例如C语言标准库函数rand()就是利用它产生随机数的。线性同余算法能够产生均匀分布的随机数,但是它依赖于给定的随机数的上限,如果上限越小,产生的随机数重复的概率就越大。
Random算法另一个缺陷是当点击“上一首”时,跟“下一首”功能完全一样,都是重新生成随机数,并利用它从播放列表中选取歌曲进行播放,而不会回到刚刚播放的那一首歌。当然,这个缺陷可以通过提供历史记录来弥补,只是需要花费额外的空间。
3.2)C/C++中的随机函数
C/C++中最常用的生成伪随机数的方法是C标准库提供的rand()函数,它定义在stdlib.h文件中,能够返回0~RAND_MAX之间均匀分布的伪随机数(RAND_MAX至少为32767,一般默认为32767)。
直接调用rand(),每次生成的伪随机序列是相同的,因为rand()在生成随机数时会使用一个种子(默认值是1),作为计算随机数的初始值,如果种子相同,那么生成的伪随机序列也将是一样的。解决的办法很简单,就是每次使用不同的种子来调用rand()函数,srand()函数就是用来设置rand()函数产生随机数时使用的种子的。
srand()函数原型如下:
1. void srand(
2. unsigned int seed
3. );
srand()和rand()配合使用的示例如下:
1. #include <stdlib.h>
2. #include <stdio.h>
3. #include <time.h>
4.
5. int main( void )
6. {
7. int i;
8.
9. /* Seed the random-number generator with current time so that
10. * the numbers will be different every time we run.
11. */
12. srand( (unsigned)time( NULL ) );
13.
14. /* Display 10 numbers. */
15. for( i = 0; i < 10;i++ )
16. printf( " %6d\n", rand() );
17.}
需要注意的一点是,上面代码在生成多个随机数时,要将srand()放到for循环的外面,否则上面输出的10个随机数都将是一样的,因为计算机运行速度太快,导致time()函数执行的结果没来得及改变。详见下图。
四 音乐随机播放算法的Shuffle实现
4.1)C/C++版本
1. #include <cstdlib>
2. #include <iostream>
3. using namespace std;
4.
5. //得到范围start~end之间的随机数
6. int rand(int start, int end)
7. {
8. return rand()%(end - start) + start;
9. }
10.
11.void swap(int* a, int* b)
12.{
13. *a = *a ^ *b;
14. *b = *a ^ *b;
15. *a = *a ^ *b;
16.}
17.void shuffle(int a[], int len)
18.{
19. int key;
20. srand((unsigned int)time(NULL));//srand应该放在for循环之外
21. for(int i = 0; i< len; i++)
22. {
23. key = rand(0, len);
24. printf("key = %d\n", key);
25. swap(a[i], a[key]); //乱序
26. }
27.}
28.
29.int main(int argc, char *argv[])
30.{
31. int a[8]={3, 5, 7, 2, 12, 1, 8, 6};
32. shuffle(a, 8);
33. for(int i = 0; i < 8; i++)
34. {
35. printf("%d\n", a[i]);
36. }
37. system("pause");
38. return 0;
39.}
4.2)Java版本
1. import java.util.Random;
2.
3. public class ASCE {
4.
5. public static void main(String arg[]) {
6. String[] musicUrl = { "/music/1.mp3", "/music/2.mp3", "/music/3.mp3",
7. "/music/4.mp3", "/music/5.mp3", "/music/6.mp3", "/music/7.mp3",
8. "/music/8.mp3", "/music/9.mp3", "/music/10.mp3" };
9.
10. shuffle(musicUrl);
11. for (String music : musicUrl) {
12. System.out.println(music);
13. }
14. }
15.
16. public static void shuffle(String[] musicUrl) {
17. int key;
18. String temp;
19. Random rand = new Random();
20.
21. for (int i = 0; i < musicUrl.length; i++) {
22. key = rand.nextInt(musicUrl.length - 1);
23. temp = musicUrl[i];
24. musicUrl[i] = musicUrl[key];
25. musicUrl[key] = temp;
26. }
27. }
28.}
五 现成的Shuffle库算法
其实无论在C++还是Java中,都已经实现了Shuffle算法,在实际项目开发中,如果不是有特殊要求的话,完全没有必要自己去实现Shuffle算法,下面就来看看已有的Shuffle算法。
5.1)C++中的Shuffle算法
C++ STL中的函数random_shuffle()就是用来对一个元素序列进行随机重新排序的算法,函数原型如下:
1. template<class RandomAccessIterator>
2. void random_shuffle(
3. RandomAccessIterator _First, //指向序列首元素的迭代器
4. RandomAccessIterator _Last //指向序列最后一个元素的下一个位置的迭代器
5. );
6. template<class RandomAccessIterator, class RandomNumberGenerator>
7. void random_shuffle(
8. RandomAccessIterator _First,
9. RandomAccessIterator _Last,
10. RandomNumberGenerator& _Rand //调用随机数产生器的函数
11. );
具体用法可参见:http://blog.csdn.net/ACE1985/article/details/5868682 。
5.2)Java中的Shuffle算法
Collections类中实现了Shuffle算法,这个类位于java.util包中,有两个重载函数,下面直接看源码:
1. public static void shuffle(List<?> list) {
2. Random rnd = r;
3. if (rnd == null)
4. r = rnd = new Random();
5. shuffle(list, rnd);
6. }
7. private static Random r;
8.
9. public static void shuffle(List<?> list, Random rnd) {
10. int size = list.size();
11. if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
12. for (int i=size; i>1; i--)
13. swap(list, i-1, rnd.nextInt(i));
14. } else {
15. Object arr[] = list.toArray();
16.
17. // Shuffle array
18. for (int i=size; i>1; i--)
19. swap(arr, i-1, rnd.nextInt(i));
20.
21. // Dump array back into list
22. ListIterator it = list.listIterator();
23. for (int i=0; i<arr.length; i++) {
24. it.next();
25. it.set(arr[i]);
26. }
27. }
28.}
参考文献:
1)http://www.ifanr.com/29498 从随机播放算法看iPod的细节之美
2)http://blog.csdn.net/cstn_kdlx/article/details/7326516 随机数生成问题小结
3)http://blog.csdn.net/hcy0727/article/details/7581671 洗牌算法
4)http://blog.csdn.net/chosen0ne/article/details/6129315 随机播放CD
5)http://blog.csdn.net/ACE1985/article/details/5868682 random_shuffle()和transform算法
转载自http://blog.csdn.net/asce1885/article/details/7582735
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。