2

我正在用java编程,但我也可以采用C++(甚至伪)代码,没问题。这就是我所在的位置:

我有类似播放列表的东西,例如List<MyPlayListItem> lsMyPlaylist. 现在我想让用户有机会洗牌,然后再回到有序列表。我的意思是,假设用户处于“随机播放模式”,播放器例如从第 7 首歌曲跳到第 5 首,但随后用户关闭了“随机播放模式”,因为他接下来想听第 6 首歌曲。你会如何处理这个问题?

我有几个想法:

  • 使用两个列表,一个是原始的,一个是随机的(存储太多)
  • 有一个 int 列表,我将其打乱,然后用作索引来获取元素(可能会好一点)
  • 使用哈希表(解决方案?不过,我可能需要一些建议)

哦,这不是家庭作业(我希望我又是那个年龄:-D)。

编辑:

我刚刚完成了这样的实现:

PlayList<E> implements List {

   private List<E> lsObjs = null;
   private List<Integer> lsIdxs = null;

   boolean bShuffleMode = false;
   int Pos = 0;
}

但是现在,我正在考虑类似的事情:

PlayListItem<E> {

   int iNextItem = 0;

}

PlayList<PlayListItem> implements List {

   private List<PlayListItem> lsObjs = null;

   boolean bShuffleMode = false;
   int Pos = 0;

}

不确定这个......仍然需要建议。如果我指定列表中的对象,我什至可以实现列表吗?嗯……

4

6 回答 6

2

如何在其上添加 nextSong 属性MyPlayListItem将保存对原始播放列表中下一首歌曲的引用。每次用户洗牌播放列表时,列表将被洗牌,但将保留原始播放列表。但是,您当然需要一些东西来引用MyPlayListItem原始播放列表中的第一个。

于 2011-01-15T04:06:40.380 回答
2

我假设你有一个没有几个 K 的移动设备。拥有两个列表不会重复列表中更大的元素。

将原始索引作为字段添加到 MyPlayListItem。将它们改组后,您可以使用比较器在索引上对它们进行排序,以将它们恢复为原始顺序。注意:除非索引小于 4 字节,否则这将使用与拥有两个列表一样多的内存。

在 32 位系统上,int[] 和 List 消耗的内存量几乎相同。(大约 16 个字节的差异)

于 2011-01-14T16:11:33.293 回答
2

我建议您有一个用于歌曲列表(库)的主容器,以及每个播放列表的容器。当然,播放列表应该指向库中的元素。

之后,有许多洗牌方法,我最喜欢的一种方法是在一个容器中拥有一个歌曲列表,您可以在其中随机挑选歌曲并删除挑选的歌曲。所以它将是随机的,但不重复播放。

我已经很久没有用 Java 编程了,所以我将给出一个 C++ 示例。我希望它简单明了:

// --*-- C++ --*--

#include <ctime>
#include <cassert>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <vector>
#include <list>

struct Song
{
    std::string name;

    Song (const std::string & name) :
        name (name)
    {
    }

    void play ()
    {
        printf ("Playing '%s'...\n", name.c_str ());
    }
};

typedef std::vector<Song> Library;
typedef std::vector<Song *> Playlist;
typedef std::vector<size_t> SongIDSet;

int
main ()
{
    srand (time (NULL));

    Library library;

    library.push_back (Song ("Lady Gaga - Bad Romance"));
    library.push_back (Song ("Rihanna - Only Girl"));
    library.push_back (Song ("Nelly - Just a Dream"));
    library.push_back (Song ("Animal - Neon Trees"));
    library.push_back (Song ("Eminem ft. Rihanna - Love The Way You Lie"));

    Playlist playlist;

    for (Library::iterator it = library.begin (),
             end_it = library.end (); it != end_it; ++it)
    {
        printf ("Added song -> %s\n", it->name.c_str ());
        playlist.push_back (&(*it));
    }

    SongIDSet shuffle;
    for (size_t i = 0, end_i = playlist.size (); i < end_i; ++i)
    {
        shuffle.push_back (i);
    }

    size_t nowPlaying = 0;

    while (!shuffle.empty ())
    {
        size_t songIndex = 0;
            printf ("Shuffle? [Y/n] ");
        switch (fgetc (stdin))
        {
            case 'N':
            case 'n':
                songIndex = nowPlaying + 1;
                fgetc (stdin); // Skip newline.
                break;
            case 'Y':
            case 'y':
                fgetc (stdin); // Skip newline.
            default:
            {
                printf ("Shuffling...\n");
                size_t index = rand () % shuffle.size ();
                assert (index >= 0);
                assert (index < shuffle.size ());
                songIndex = shuffle[index];
                shuffle.erase (shuffle.begin () + index);
            }
        }
        assert (songIndex >= 0);
        if (songIndex < playlist.size ())
        {
            nowPlaying = songIndex;
            playlist[nowPlaying]->play ();
        }
        else
        {
            break; // Done playing.. Repeat maybe?
        }
    }
}

这是一个示例运行/输出:

$ ./test 
Added song -> Lady Gaga - Bad Romance
Added song -> Rihanna - Only Girl
Added song -> Nelly - Just a Dream
Added song -> Animal - Neon Trees
Added song -> Eminem ft. Rihanna - Love The Way You Lie
Shuffle? [Y/n] 
Shuffling...
Playing 'Eminem ft. Rihanna - Love The Way You Lie'...
Shuffle? [Y/n] 
Shuffling...
Playing 'Nelly - Just a Dream'...
Shuffle? [Y/n] 
Shuffling...
Playing 'Rihanna - Only Girl'...
Shuffle? [Y/n] 
Shuffling...
Playing 'Animal - Neon Trees'...
Shuffle? [Y/n] 
Shuffling...
Playing 'Lady Gaga - Bad Romance'...
$ ./test 
Added song -> Lady Gaga - Bad Romance
Added song -> Rihanna - Only Girl
Added song -> Nelly - Just a Dream
Added song -> Animal - Neon Trees
Added song -> Eminem ft. Rihanna - Love The Way You Lie
Shuffle? [Y/n] 
S    huffling...
Playing 'Nelly - Just a Dream'...
Shuffle? [Y/n] n
Playing 'Animal - Neon Trees'...
Shuffle? [Y/n] n
Playing 'Eminem ft. Rihanna - Love The Way You Lie'...
Shuffle? [Y/n] n
于 2011-01-14T16:44:00.983 回答
1

如果内存是您最大的限制,您可以在每首歌曲的结尾选择一首随机歌曲播放。这显然意味着您不必在重新开始播放列表之前播放每首歌曲。:)

如果您需要在再次开始播放歌曲之前播放每首歌曲,则存储一个长度等于歌曲数量的位串。当您播放歌曲时,设置与该索引对应的位。如果设置了位,则永远不要播放歌曲,而是在此时增加索引,直到您在未设置的字符串中找到位。如果设置了字符串中的所有位,则重置位串。

于 2011-01-14T16:22:14.053 回答
1

简单的东西呢?

在列表中使用索引指针,比如一个整数。这是当前正在播放的歌曲。当播放器处于随机播放模式时,该指针被设置为介于 0 和列表中项目数 - 1 之间的随机数。当播放器处于顺序播放模式时,该指针简单地递增。

如果要防止歌曲重复,有两种策略。一种是使用位串,正如上面另一个人所建议的那样。另一种是使用一套。每次设置指针时,检查集合中的成员。如果它已经在集合中,请获取另一个索引。如果不是,则添加它并播放歌曲。两者都将达到相同的效果。

当已播放歌曲与未播放歌曲的比率变高且随机索引始终在列表中时,您将遇到问题。

于 2011-01-14T16:36:18.430 回答
0

您可以有两个项目:
1)列表中的真实项目列表
2)具有整数索引的向量

当随机播放被激活时,您可以随机播放索引。当它关闭时,对索引进行排序。访问列表中的元素时,使用索引。

像这样的东西:

std::list< MyListElement > elements = ...;
std::vector< int > indexes = ...;

// shuffle off
sort( indexes.begin(), indexes.end() );

// get elements
elements[ indexes[ i ] ];
于 2011-01-14T16:23:26.377 回答