c++向量随机洗牌它的一部分

发布于 2024-08-09 18:10:04 字数 96 浏览 7 评论 0原文

随机排列向量中一定比例的元素的最佳方法是什么?

假设我想要 10% 或 90% 的向量被打乱。 不一定是前 10%,而是全面的 10%。

TIA

Whats the best way to shuffle a certain percentage of elements in a vector.

Say I want 10% or 90% of the vector shuffled.
Not necessarily the first 10% but just 10% across the board.

TIA

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

绳情 2024-08-16 18:10:04

修改 Fisher-Yates 洗牌以对数组中 10% 的索引不执行任何操作。

这是我发布(来自维基百科)并修改的java代码,但我认为你可以将其翻译为C++,因为这更多的是一个算法问题而不是语言问题。

public static void shuffleNinetyPercent(int[] array) 
{
    Random rng = new Random();       // java.util.Random.
    int n = array.length;            // The number of items left to shuffle (loop invariant).
    while (n > 1) 
    {
        n--;                         // n is now the last pertinent index
        if (rng.nextDouble() < 0.1) continue; //<-- ADD THIS LINE
        int k = rng.nextInt(n + 1);  // 0 <= k <= n.
        // Simple swap of variables
        int tmp = array[k];
        array[k] = array[n];
        array[n] = tmp;
    }
}

Modify a Fisher-Yates shuffle to do nothing on 10% of the indices in the array.

This is java code that I'm posting (from Wikipedia) and modifying, but I think you can make the translation to C++, because this is more of an algorithms problem than a language problem.

public static void shuffleNinetyPercent(int[] array) 
{
    Random rng = new Random();       // java.util.Random.
    int n = array.length;            // The number of items left to shuffle (loop invariant).
    while (n > 1) 
    {
        n--;                         // n is now the last pertinent index
        if (rng.nextDouble() < 0.1) continue; //<-- ADD THIS LINE
        int k = rng.nextInt(n + 1);  // 0 <= k <= n.
        // Simple swap of variables
        int tmp = array[k];
        array[k] = array[n];
        array[n] = tmp;
    }
}
玻璃人 2024-08-16 18:10:04

您可以尝试以下操作:

为向量的每个元素分配一个随机数。对随机数位于您分配的随机数中最小 10% 的元素进行洗牌:您甚至可以想象用占位符替换向量中的 10%,然后根据随机数对 10% 进行排序,然后将它们插入回占位符所在的向量。

You could try this:

Assign a random number to each element of the vector. Shuffle the elements whose random number is in the smallest 10% of the random numbers you assigned: You could even imagine replacing that 10% in the vector with placeholders, then sort your 10% according to their random number, and insert them back into the vector where your placeholders are.

凤舞天涯 2024-08-16 18:10:04

编写自己的随机迭代器并使用 random_shuffle 怎么样,如下所示:(完全未经测试,只是为了得到一个想法)

template<class T>
class myRandomIterator : public std::iterator<std::random_access_iterator_tag, T>
{
public:
    myRandomIterator(std::vector<T>& vec, size_t pos = 0): myVec(vec), myIndex(0), myPos(pos)
    {
        srand(time(NULL));
    }

    bool operator==(const myRandomIterator& rhs) const
    {
        return myPos == rhs.myPos;
    }

    bool operator!=(const myRandomIterator& rhs) const
    {
        return ! (myPos == rhs.myPos);
    }

    bool operator<(const myRandomIterator& rhs) const
    {
        return myPos < rhs.myPos;
    }

    myRandomIterator& operator++() 
    {
        ++myPos;
        return fill();
    }

    myRandomIterator& operator++(int) 
    {
        ++myPos;
        return fill();
    }

    myRandomIterator& operator--() 
    {
        --myPos;
        return fill();
    }

    myRandomIterator& operator--(int)
    {
        --myPos;
        return fill();
    }



    myRandomIterator& operator+(size_t n) 
    {
        ++myPos;
        return fill();
    }

    myRandomIterator& operator-(size_t n) 
    {
        --myPos;
        return fill();
    }


    const T& operator*() const
    {
        return myVec[myIndex];
    }

    T& operator*()
    {
        return myVec[myIndex];
    }



private:
    myRandomIterator& fill()
    {
        myIndex = rand() % myVec.size();
        return *this;
    }

private:
    size_t myIndex;
    std::vector<T>& myVec;
    size_t myPos;

};

int main()
{
    std::vector<int> a;
    for(int i = 0; i < 100; ++i)
    {
        a.push_back(i);
    }

    myRandomIterator<int> begin(a);
    myRandomIterator<int> end(a, a.size() * 0.4);

    std::random_shuffle(begin, end);

    return 0;
}

How about writing your own random iterator and using random_shuffle, something like this: (Completely untested, just to get an idea)

template<class T>
class myRandomIterator : public std::iterator<std::random_access_iterator_tag, T>
{
public:
    myRandomIterator(std::vector<T>& vec, size_t pos = 0): myVec(vec), myIndex(0), myPos(pos)
    {
        srand(time(NULL));
    }

    bool operator==(const myRandomIterator& rhs) const
    {
        return myPos == rhs.myPos;
    }

    bool operator!=(const myRandomIterator& rhs) const
    {
        return ! (myPos == rhs.myPos);
    }

    bool operator<(const myRandomIterator& rhs) const
    {
        return myPos < rhs.myPos;
    }

    myRandomIterator& operator++() 
    {
        ++myPos;
        return fill();
    }

    myRandomIterator& operator++(int) 
    {
        ++myPos;
        return fill();
    }

    myRandomIterator& operator--() 
    {
        --myPos;
        return fill();
    }

    myRandomIterator& operator--(int)
    {
        --myPos;
        return fill();
    }



    myRandomIterator& operator+(size_t n) 
    {
        ++myPos;
        return fill();
    }

    myRandomIterator& operator-(size_t n) 
    {
        --myPos;
        return fill();
    }


    const T& operator*() const
    {
        return myVec[myIndex];
    }

    T& operator*()
    {
        return myVec[myIndex];
    }



private:
    myRandomIterator& fill()
    {
        myIndex = rand() % myVec.size();
        return *this;
    }

private:
    size_t myIndex;
    std::vector<T>& myVec;
    size_t myPos;

};

int main()
{
    std::vector<int> a;
    for(int i = 0; i < 100; ++i)
    {
        a.push_back(i);
    }

    myRandomIterator<int> begin(a);
    myRandomIterator<int> end(a, a.size() * 0.4);

    std::random_shuffle(begin, end);

    return 0;
}
絕版丫頭 2024-08-16 18:10:04

一种方法可以使用 std::random_shuffle() ,通过控制输入范围来控制 % ....

one way may using , std::random_shuffle() , control % by controlling input range ....

月亮邮递员 2024-08-16 18:10:04

为什么不对随机选择的位置进行 N 次交换,其中 N 由百分比决定?

因此,如果我有 100 个元素,则 10% 的随机播放将执行 10 次交换。每次交换都会随机选择数组中的两个元素并交换它们。

Why not perform N swaps of randomly selected positions, where N is determined by the percentage?

So if I have 100 elements, a 10% shuffle will perform 10 swaps. Each swap randomly picks two elements in the array and switches them.

东走西顾 2024-08-16 18:10:04

如果您有 SGI 的 std::random_sample 扩展,你可以这样做。如果没有,很容易在返回指定范围内均匀分布的随机整数的函数之上实现random_sample(Knuth,第 2 卷,“算法 R”)。

#include <algorithm>
#include <vector>
using std::vector;

void shuffle_fraction(vector<int> &data, double fraction) {
    assert(fraction >= 0.0 && fraction <= 1.0);

    // randomly choose the indices to be shuffled
    vector<int> bag(data.size());
    for(int i = 0; i < bag.size(); ++i) bag[i] = i;

    vector<int> selected(static_cast<int>(data.size() * fraction));
    std::random_sample(bag.begin(), bag.end(), selected.begin(), selected.end());

    // take a copy of the values being shuffled
    vector<int> old_value(selected.size());
    for (int i = 0; i < selected.size(); ++i) {
        old_value[i] = data[selected[i]];
    }

    // choose a new order for the selected indices
    vector<int> shuffled(selected);
    std::random_shuffle(shuffled.begin(), shuffled.end());

    // apply the shuffle to the data: each of the selected indices
    // is replaced by the value for the corresponding shuffled indices
    for (int i = 0; i < selected.size(); ++i) {
        data[selected[i]] = old_value[shuffled[i]];
    }
}

不是最有效的,因为它使用三个“小”向量,但避免了必须调整 Fisher-Yates 算法来对向量的子集进行操作。在实践中,您可能希望这是一个在一对随机访问迭代器而不是向量上运行的函数模板。我没有这样做,因为我认为这会使代码有点混乱,而且你也没有要求这样做。我还会采用尺寸而不是比例,由调用者决定如何对分数进行舍入。

If you have SGI's std::random_sample extension, you can do this. If not, it's easy to implement random_sample on top of a function which returns uniformly-distributed random integers in a specified range (Knuth, Volume 2, "Algorithm R").

#include <algorithm>
#include <vector>
using std::vector;

void shuffle_fraction(vector<int> &data, double fraction) {
    assert(fraction >= 0.0 && fraction <= 1.0);

    // randomly choose the indices to be shuffled
    vector<int> bag(data.size());
    for(int i = 0; i < bag.size(); ++i) bag[i] = i;

    vector<int> selected(static_cast<int>(data.size() * fraction));
    std::random_sample(bag.begin(), bag.end(), selected.begin(), selected.end());

    // take a copy of the values being shuffled
    vector<int> old_value(selected.size());
    for (int i = 0; i < selected.size(); ++i) {
        old_value[i] = data[selected[i]];
    }

    // choose a new order for the selected indices
    vector<int> shuffled(selected);
    std::random_shuffle(shuffled.begin(), shuffled.end());

    // apply the shuffle to the data: each of the selected indices
    // is replaced by the value for the corresponding shuffled indices
    for (int i = 0; i < selected.size(); ++i) {
        data[selected[i]] = old_value[shuffled[i]];
    }
}

Not the most efficient, since it uses three "small" vectors, but avoids having to adapt the Fisher-Yates algorithm to operate on a subset of the vector. In practice you'd probably want this to be a function template operating on a pair of random-access iterators rather than a vector. I haven't done that because I think it would obfuscate the code a little, and you didn't ask for it. I'd also take a size instead of a proportion, leaving it up to the caller to decide how to round fractions.

一生独一 2024-08-16 18:10:04

您可以使用 shuffle bag 算法来选择数组的 10%。然后对该选择使用正常的随机播放。

you can use the shuffle bag algorithm to select 10% of your array. Then use the normal shuffle on that selection.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文