我在接受采访时被问到这个问题而且我提出了各种解决方案,但面试官并不相信。我有兴趣找到解决方案。请提出您的意见:
问:编写一个有效的数据结构来实现ipod中的shuffle。它必须播放所有歌曲,每次以不同的随机顺序播放,同一首歌不应该重复。 (主要是O(n))
一个解决方案,我在采访后想到了:我可以做一个随机的快速排序,没有递归。我们随机选择1个轴O(1)然后做快速排序O(n)。现在歌曲将按某种顺序排序,然后我将它们播放到最后。一旦它到达终点,我将再次选择一个随机的枢轴,并一次又一次地重复这个过程。
此致 Sethu
答案 0 :(得分:8)
你想要Fisher-Yates shuffle。请注意该页面上提到的实施错误,因为您当前接受的答案与一个错误相违背。
答案 1 :(得分:3)
将所有歌曲放在一个数组中...... 对于数组中的每个元素,将其与随机位置交换。
答案 2 :(得分:1)
嗯,首先想到的线性时间解决方案:
您可以创建所有歌曲的链接列表,这将占用大约O(n)(假设插入是恒定时间操作)。然后,生成一个随机数,以模块的大小为模以获得随机索引,并删除该索引并将其附加到新列表(两者都是常量时间操作)。
每个O(n)的插入+每个O(n)+第二插入O(n)的去除。这将总体上导致线性时间解决方案。
编辑:我完全忘了走在列表中。因此,您可以将结果设为固定长度的数组。弹出链表的头部,为其分配随机索引,并填充数组。
答案 3 :(得分:1)
Nate(编辑)和Brian的算法是Fisher-Yates shuffle O(n),而排序改组是O(nlogn),但实际上可能更快(http://en.wikipedia.org/wiki /费舍尔%E2%80%93Yates_shuffle#Comparison_with_other_shuffling_algorithms)。让歌曲改组错误可能会产生微不足道的后果,但如果你正在为在线扑克游戏编写一个改组算法,请确保你知道自己在做什么(http://www.cigital.com/news/index.php?pg=艺术与artid的数据类型= 20)。
答案 4 :(得分:0)
我是初学者,让我说一个令人深思的解决方案,如果有任何问题请告诉我。
让我们假设歌曲存储在单链或双链表中。每次打开音乐播放器时,选择一个小于(你想要的任何数字)的随机数假设k,并反转列表中的每个k个节点,同样做两次或最多三次(如你所愿),这将需要O( 2n)或O(3n)时间洗牌。 最后有一个指向列表最后一个节点的指针。 每次收听一首歌曲(访问一个节点)时,删除该节点并将其插入最后一个节点旁边,这可以在O(1)时间内完成。 这一直持续到音乐播放器关闭。
谢谢, 渴望知道答案的正确性。
答案 5 :(得分:0)
你想要的是Fisher-Yates Shuffle。这是java中的一个实现:
public void shuffle(Song[] songs) {
Random r = new Random();
for(int i = 0; i < songs.length - 1; i++) {
int swap = i + r.nextInt(songs.length-1-i);
T temp = songs[i];
songs[i] = songs[swap];
songs[swap] = temp;
}
}
/* r.nextInt(max) returns integer 0 to max-1 inclusive */
它是如何工作的,它将整个数组视为一个帽子,并开始拉随机元素并将它们排列在数组的前面。 i
之后的所有元素都在“桶中”,i
之前的所有元素都被洗牌。