我试图通过递归方式对链表进行洗牌,将其分成两个列表然后合并它们以确保随机随机播放。
我面临的两个问题是:
PS - 我通过互联网搜索发现,2个列表的长度应该相同,以确保随机性,但我不知道它背后的逻辑。另外,请告诉我是否有更好的方法比我正在尝试。
提前致谢!
public class LinkedListShuffle
{
static public class LinkedList<E> // static nested class
{
private int N = 0;
private Node first = null;
public class Node
{
E elem;
Node next;
}
public boolean isEmpty()
{ return N == 0; }
public void push (E elem)
{
Node oldfirst = first;
first = new Node();
first.elem = elem;
first.next = oldfirst;
N++;
}
public E pop()
{
E elem = first.elem;
first = first.next;
N--;
return elem;
}
public int size ()
{ return N; }
}
public static void shuffle(LinkedList l)
{
if (l.size() == 1) return;
LinkedList.Node current = l.first;
LinkedList l1 = new LinkedList();
LinkedList l2 = new LinkedList();
while (! l.isEmpty())
{
l1.push(l.pop());
if (! l.isEmpty()) l2.push(l.pop());
}
shuffle(l1);
shuffle(l2);
/*------------------------------------------
* if (l2.size() < l1.size())
* introduce a dummy node to ensure the
* randomness in the process of shuffling
-----------------------------------------*/
merge(l, l1, l2);
/*-----------------------------------------------
* remove the dummy variable
* ----------------------------------------------*/
}
public static void merge (LinkedList l, LinkedList l1, LinkedList l2)
{
while (l1.size() != 0 && l2.size() != 0)
{
double chance = StdRandom.uniform(1);
if (chance < 0.5) l.push(l1.pop());
else l.push(l2.pop());
}
if (! l1.isEmpty())
while (! l1.isEmpty()) l.push(l1.pop());
if (! l2.isEmpty())
while (! l2.isEmpty()) l.push(l2.pop());
}
public static void main (String[] args)
{
LinkedList<String> l = new LinkedList<String>();
LinkedList<String> copy = new LinkedList<String>();
l.push("A"); l.push("B"); l.push("C"); l.push("D");
l.push("E"); l.push("F"); l.push("G"); l.push("H");
copy = l;
while (copy.size() != 0) StdOut.println(copy.pop()+" ");
shuffle(l);
while (l.size() != 0) StdOut.println(l.pop()+" ");
}
}
答案 0 :(得分:1)
您的问题是,在调用shuffle(l)
之前,在主方法中打印时,您正在清空列表。
您正在将列表l
分配给名为copy
的变量,但此变量不包含列表的副本。它指的是同一个列表。当您致电copy.pop()
时,您会从原始列表中删除一个元素。因此,您在空列表中调用shuffle
。
public static void main (String[] args)
{
LinkedList<String> l = new LinkedList<String>();
LinkedList<String> copy = new LinkedList<String>();
l.push("A"); l.push("B"); l.push("C"); l.push("D");
l.push("E"); l.push("F"); l.push("G"); l.push("H");
copy = l;
while (copy.size() != 0) StdOut.println(copy.pop()+" "); // remove this line
// and your method will
// work
shuffle(l);
while (l.size() != 0) StdOut.println(l.pop()+" ");
}
当然,这意味着您的shuffle
方法无法将空列表作为输入处理。
这可以通过微小的解决方案来解决:
public static void shuffle(LinkedList l)
{
if (l.size() <= 1) return; // instead of == 1
...
答案 1 :(得分:0)
我认为随机性可以在分裂阶段引入,在这种情况下,合并只需要连接2个随机混乱的列表。以下是使用Robert Sedgewick的算法课程中的LinkedBag
链接列表实现的实现,这显然是您从中完成作业的地方。
public static <T> LinkedBag<T> shuffle(LinkedBag<T> ll) {
if (ll.size() <= 1) return ll;
LinkedBag<T>[] sublists = split(ll);
LinkedBag<T> l1 = shuffle(sublists[0]);
LinkedBag<T> l2 = shuffle(sublists[1]);
return merge(l1, l2);
}
private static <T> LinkedBag<T>[] split(LinkedBag<T> ll) {
LinkedBag<T> l1 = new LinkedBag<>();
LinkedBag<T> l2 = new LinkedBag<>();
Iterator<T> it = ll.iterator();
while (it.hasNext()) {
if (StdRandom.bernoulli())
l1.add(it.next());
else
l2.add(it.next());
}
return (LinkedBag<T>[]) new LinkedBag<?>[]{l1, l2};
}
private static <T> LinkedBag<T> merge(LinkedBag<T> l1, LinkedBag<T> l2) {
Iterator<T> it = l2.iterator();
while (it.hasNext()) {
l1.add(it.next());
}
return l1;
}