c ++ vector随机shuffle的一部分

时间:2009-11-03 14:23:24

标签: c++ vector shuffle

什么是在矢量中移动一定比例元素的最佳方法。

说我想要10%或90%的矢量洗牌。 不一定是前10%,而是全面只有10%。

TIA

7 个答案:

答案 0 :(得分:4)

修改Fisher-Yates shuffle,不对数组中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;
    }
}

答案 1 :(得分:2)

如何编写自己的随机迭代器并使用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;
}

答案 2 :(得分:2)

你可以试试这个:

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

答案 3 :(得分:1)

单向可以使用std :: random_shuffle(),通过控制输入范围控制%....

答案 4 :(得分:1)

为什么不执行N个随机选择的位置,其中N由百分比确定?

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

答案 5 :(得分:1)

如果您有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算法适应向量的子集。在实践中,您可能希望这是一个在一对随机访问迭代器而不是向量上运行的函数模板。我没有这样做,因为我认为它会使代码混淆一点,而你没有要求它。我也会选择一个大小而不是一个比例,然后由调用者来决定如何对分数进行舍入。

答案 6 :(得分:0)

您可以使用随机包算法选择10%的数组。然后在该选择上使用正常的shuffle。