如何取消名单?

时间:2014-06-14 16:56:02

标签: java android algorithm sorting

我正在使用Collections.shuffle(list); 洗牌清单,但我不知道如何取消洗牌?我想在洗牌之前保存列表,然后将其洗牌,以便维护备份,并且可以在需要时重新恢复,但这似乎是一种低效的方式它会花费时间和记忆....如果你知道一种更合乎逻辑的方式,你能详细说明吗? 顺便说一句,这是我的应用程序的样子:D

enter image description here

enter image description here

6 个答案:

答案 0 :(得分:5)

没有这种无拘无束的概念 - 例如,在你洗牌后,你会如何回到以前的状态?

如果您的原始收藏品以某种明确的方式订购,请再次对其进行排序。否则(例如,如果它是手工订购的),你必须在你洗牌之前复制一份。

理论上你可以

  • 生成随机种子并记住它
  • 创建Random并将其传递到shuffle
  • 稍后,创建一个从{0到大小(独家)
  • ArrayList<Integer>
  • 使用原始种子
  • 创建的新Random随机播放该列表
  • 使用结果计算每个项目的原始索引(因为您知道每个原始项目在洗牌列表中的最终位置)

......但这是一项非常多的工作。除非你的集合真的太大而不能保留额外的副本(不要忘记它只是引用的副本,而不是整个对象),我只是在改组之前克隆该集合。

答案 1 :(得分:4)

首先,应该使用Jon的答案,因为这是最简单和最干净的。无论如何,可以用已知的随机源来反转混洗,因为Collections.shuffle()指定了使用的算法。再一次,不要这样做,但这里是任何好奇的人的过程:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

public class Unshuffle {
    public static void main(String[] args) {
        List<Integer> data = new ArrayList<Integer>();
        for (int i = 0; i < 20; i++) {
            data.add(i);
        }
        System.out.println(data);
        Collections.shuffle(data, new Random(42));
        System.out.println(data);
        unshuffle(data, new Random(42));
        System.out.println(data);
    }

    private static <T> void unshuffle(List<T> list, Random rnd) {
        int[] seq = new int[list.size()];
        for (int i = seq.length; i >= 1; i--) {
            seq[i - 1] = rnd.nextInt(i);
        }
        for (int i = 0; i < seq.length; i++) {
            Collections.swap(list, i, seq[i]);
        }
    }
}

输出是:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[15, 16, 14, 13, 5, 11, 17, 18, 8, 2, 6, 7, 3, 1, 19, 4, 12, 0, 9, 10]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

答案 2 :(得分:0)

使用Collections.sort()将其排序回任何顺序(字母,数字等)

答案 3 :(得分:0)

我们没有洗牌清单,我们只是随机播放,随机播放 最简单的方法是从Collections调用shuffle方法并传递arraylist

List<String> myArrayList = new ArrayList<String>;
myArrayList.add("A");
myArrayList.add("B");
myArrayList.add("C");
myArrayList.add("D");
Collections.shuffle(myArrayList);

迭代列表。它被洗牌了。

答案 4 :(得分:0)

为列表中的每个项目添加额外的隐藏索引字段。在改组之前,为这个隐藏字段分配顺序号码:1,2,3,4,5 ......如果你想让列表恢复原来的顺序,只需对这个隐藏字段进行排序。

您需要足够的空间来存储隐藏的字段和少量的处理时间。

答案 5 :(得分:0)

我知道这很老了,但我可以自由实施*乔恩·斯凯特(Jon Skeet)的理论改组,因为这是一个很棒的主意。 PcgRandom算法的功能是允许人们“跳”到随机数生成器中的任意点,并且可以用来“记住”随机播放期间生成的值,并将其反转:

var currentIndex = m_currentIndex;
var lastIndex = (m_values.Length - 1);

while (-1 < currentIndex) {
    m_randomNumberGenerator.Jump(-1);

    var randomIndex = m_randomNumberGenerator.NextInt32(currentIndex, lastIndex);
    var tempValue = m_values[randomIndex];

    m_values[randomIndex] = m_values[currentIndex];
    m_values[currentIndex--] = tempValue;

    m_randomNumberGenerator.Jump(-1);
}

这是随机数生成器的完整实现:​​

/// <summary>
/// Represents an instance of a fast random number generator; relies on the Pcg32XshRr algorithm described by Melissa O'neil.
/// </summary>
/// <remarks>
/// http://pcg-random.org/paper.html
/// https://en.wikipedia.org/wiki/Lehmer_random_number_generator
/// https://en.wikipedia.org/wiki/Linear_congruential_generator
/// https://github.com/lemire/fastrange
/// </remarks>
public sealed class FastRandom : IRandomNumberGenerator
{
    private const ulong MAX_STREAM_VALUE = ((1UL << 63) - 1UL);

    private readonly ulong m_magic;
    private readonly ulong m_stream;

    private ulong m_state;

    /// <summary>
    /// Gets the default <see cref="FastRandom"/> instance.
    /// </summary>
    public static readonly FastRandom Default = new FastRandom();

    /// <summary>
    /// Initializes a new instance of the <see cref="FastRandom"/> class.
    /// </summary>
    /// <param name="state">The initial state of the random number generator.</param>
    /// <param name="stream">The stream offset of the random number generator.</param>
    [CLSCompliant(false)]
    public FastRandom(ulong state, ulong stream) {
        if (stream > MAX_STREAM_VALUE) {
            throw new ArgumentOutOfRangeException(message: "stream offset must be a positive integer less than 2^63", paramName: nameof(stream));
        }

        m_magic = 6364136223846793005UL;
        m_state = state;
        m_stream = ((((~(stream & 1UL)) << 63) | stream) | 1UL);
    }
    /// <summary>
    /// Initializes a new instance of the <see cref="FastRandom"/> class.
    /// </summary>
    /// <param name="state">The initial state of the random number generator.</param>
    /// <param name="stream">The stream offset of the random number generator.</param>
    public FastRandom(long state, long stream) : this(checked((ulong)state), checked((ulong)stream)) { }
    /// <summary>
    /// Initializes a new instance of the <see cref="FastRandom"/> class.
    /// </summary>
    /// <param name="state">The initial state of the random number generator.</param>
    [CLSCompliant(false)]
    public FastRandom(ulong state) : this(state, SecureRandom.Default.NextUInt64(0UL, MAX_STREAM_VALUE)) { }
    /// <summary>
    /// Initializes a new instance of the <see cref="FastRandom"/> class.
    /// </summary>
    /// <param name="state">The initial state of the random number generator.</param>
    public FastRandom(long state) : this((ulong)state) { }
    /// <summary>
    /// Initializes a new instance of the <see cref="FastRandom"/> class.
    /// </summary>
    public FastRandom() : this(SecureRandom.Default.NextUInt64()) { }

    /// <summary>
    /// Moves the state of the generator forwards by the specificed number of steps.
    /// </summary>
    /// <param name="count">The number of states that will be jumped.</param>
    [CLSCompliant(false)]
    public void Jump(ulong count) {
        Jump(ref m_state, m_magic, m_stream, count);
    }
    /// <summary>
    /// Moves the state of the generator forwards or backwards by the specificed number of steps.
    /// </summary>
    /// <param name="count">The number of states that will be jumped.</param>
    public void Jump(long count) {
        Jump(ref m_state, m_magic, m_stream, unchecked((ulong)count));
    }
    /// <summary>
    /// Generates a uniformly distributed double precision floating point value between the exclusive range (0, 1).
    /// </summary>
    public double NextDouble() {
        return Operations.DoornikDouble(NextInt32(), NextInt32());
    }
    /// <summary>
    /// Generates a uniformly distributed 32-bit signed integer between the range of int.MinValue and int.MaxValue.
    /// </summary>
    public int NextInt32() {
        return ((int)NextUInt32());
    }
    /// <summary>
    /// Generates a uniformly distributed 32-bit signed integer between the inclusive range [x, y].
    /// </summary>
    /// <param name="x">The value of x.</param>
    /// <param name="y">The value of y.</param>
    public int NextInt32(int x, int y) {
        if (x > y) {
            var z = x;

            x = y;
            y = z;
        }

        var range = ((uint)(y - x));

        if (range != uint.MaxValue) {
            return ((int)(Sample(ref m_state, m_magic, m_stream, exclusiveHigh: (range + 1U)) + x));
        }
        else {
            return NextInt32();
        }
    }
    /// <summary>
    /// Generates a uniformly distributed single precision floating point value between the exclusive range (0, 1).
    /// </summary>
    public float NextSingle() {
        return Operations.DoornikSingle(NextInt32());
    }
    /// <summary>
    /// Generates a uniformly distributed 32-bit unsigned integer between the range of uint.MinValue and uint.MaxValue.
    /// </summary>
    [CLSCompliant(false)]
    public uint NextUInt32() {
        return Next(ref m_state, m_magic, m_stream);
    }
    /// <summary>
    /// Generates a uniformly distributed 32-bit unsigned integer between the inclusive range [x, y].
    /// </summary>
    /// <param name="x">The value of x.</param>
    /// <param name="y">The value of y.</param>
    [CLSCompliant(false)]
    public uint NextUInt32(uint x, uint y) {
        if (x > y) {
            var z = x;

            x = y;
            y = z;
        }

        var range = (y - x);

        if (range != uint.MaxValue) {
            return (Sample(ref m_state, m_magic, m_stream, exclusiveHigh: (range + 1U)) + x);
        }
        else {
            return NextUInt32();
        }
    }

    private static void Jump(ref ulong state, ulong magic, ulong stream, ulong count) {
        var accMul = 1UL;
        var accAdd = 0UL;
        var curMul = magic;
        var curAdd = stream;

        while (count > 0UL) {
            if (0UL < (count & 1UL)) {
                accMul *= curMul;
                accAdd = ((accAdd * curMul) + curAdd);
            }

            curAdd = ((curMul + 1UL) * curAdd);
            curMul *= curMul;
            count >>= 1;
        }

        state = ((accMul * state) + accAdd);
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static uint Next(ref ulong state, ulong magic, ulong stream) {
        state = unchecked((state * magic) + stream);

        return Operations.RotateRight(value: ((uint)(((state >> 18) ^ state) >> 27)), count: ((int)(state >> 59)));
    }
    private static uint Sample(ref ulong state, ulong magic, ulong stream, uint exclusiveHigh) {
        ulong sample = Next(ref state, magic, stream);
        ulong result = (sample * exclusiveHigh);
        uint leftover = ((uint)result);

        if (leftover < exclusiveHigh) {
            uint threshold = ((((uint)(-exclusiveHigh)) % exclusiveHigh));

            while (leftover < threshold) {
                sample = Next(ref state, magic, stream);
                result = (sample * exclusiveHigh);
                leftover = ((uint)result);
            }
        }

        return ((uint)(result >> 32));
    }
}

以及随机播放逻辑的完整实现:​​

/// <summary>
/// Represents a strongly typed collection that uses a random number generator to retrieve elements.
/// </summary>
/// <typeparam name="T">The type of elements encapsulated by the bag.</typeparam>
public sealed class ShuffleBag<T> : IEnumerable<T>, IEnumerator<T>
{
    private readonly IRandomNumberGenerator m_randomNumberGenerator;
    private readonly T[] m_values;

    private int m_currentIndex;

    /// <summary>
    /// Gets the element in the collection at the current position of the enumerator.
    /// </summary>
    object IEnumerator.Current => Current;
    /// <summary>
    /// Gets the element in the collection at the current position of the enumerator.
    /// </summary>
    public T Current => m_values[m_currentIndex];

    /// <summary>
    /// Initializes a new instance of the <see cref="ShuffleBag{T}"/> class.
    /// </summary>
    /// <param name="randomNumberGenerator">The source of random numbers that will be used to perform the shuffle.</param>
    /// <param name="values">The array of values that will be randomized.</param>
    public ShuffleBag(IRandomNumberGenerator randomNumberGenerator, T[] values) {
        if (randomNumberGenerator.IsNull()) {
            throw new ArgumentNullException(message: "random number generator cannot be null", paramName: nameof(randomNumberGenerator));
        }

        if (values.IsNull()) {
            throw new ArgumentNullException(message: "array of values cannot be null", paramName: nameof(values));
        }

        m_currentIndex = -1;
        m_randomNumberGenerator = randomNumberGenerator;
        m_values = values;
    }

    /// <summary>
    /// Releases all resources used by this <see cref="ShuffleBag"/> instance.
    /// </summary>
    public void Dispose() { }
    /// <summary>
    /// Returns an enumerator that randomly yields elements from the bag.
    /// </summary>
    IEnumerator IEnumerable.GetEnumerator() {
        return GetEnumerator();
    }
    /// <summary>
    /// Returns an enumerator that randomly yields elements from the bag.
    /// </summary>
    public IEnumerator<T> GetEnumerator() {
        while (MoveNext()) {
            yield return Current;
        }
    }
    /// <summary>
    /// Advances the enumerator to the next random element in the collection.
    /// </summary>
    public bool MoveNext() {
        var currentIndex = m_currentIndex;
        var lastIndex = (m_values.Length - 1);

        if (currentIndex < lastIndex) {
            var randomIndex = m_randomNumberGenerator.NextInt32(++currentIndex, lastIndex);
            var tempValue = m_values[randomIndex];

            m_currentIndex = currentIndex;
            m_values[randomIndex] = m_values[currentIndex];
            m_values[currentIndex] = tempValue;

            return true;
        }
        else {
            return false;
        }
    }
    /// <summary>
    /// Sets the enumerator to its initial position.
    /// </summary>
    /// <param name="unshuffle">Indicates whether elements will be returned to their original, unshuffled, positions.</param>
    public void Reset(bool unshuffle) {
        if (unshuffle) {
            var currentIndex = m_currentIndex;
            var lastIndex = (m_values.Length - 1);

            while (-1 < currentIndex) {
                m_randomNumberGenerator.Jump(-1);

                var randomIndex = m_randomNumberGenerator.NextInt32(currentIndex, lastIndex);
                var tempValue = m_values[randomIndex];

                m_values[randomIndex] = m_values[currentIndex];
                m_values[currentIndex--] = tempValue;

                m_randomNumberGenerator.Jump(-1);
            }
        }

        m_currentIndex = -1;
    }
    /// <summary>
    /// Sets the enumerator to its initial position and returns elements to their original, unshuffled, positions.
    /// </summary>
    public void Reset() {
        Reset(unshuffle: true);
    }
}

*对不起,它在C#中。