一个打乱列表获得伪随机序列的生成器

一个打乱列表获得伪随机序列的生成器

  • 偶得一代码,再晚也要记录下来。最近看一本叫游戏编程的书,里面讲到了一种用伪随机的方式实现的洗牌算法。
算法思想是这样的:
算法利用质数和二次方程的数学特性,该算法需要一个质数,他应该大于要遍历的集合元素个数。如果集合中有10个元素,该指数为11,当然这个算法不会生成质数;它只是将一组选定的质数放在一个查询表中。如果需要比较大的质数可以另行生成。其工作原理如下:用3个大于0的随机数计算出一个跳跃值(skip)。这些随机数作为二次方程的系数,而阈值(x)被设置为集合的元素个数;
跳跃值 = 随机数A x (元素个数 x 元素个数)+(随机数B x 元素个数)+随机数C
skip = RandomA * (members * members)+(RandomB * members)+RandomC
有了跳跃值(skip)后,就可以使用下面的代码,以伪随机顺序遍历一次整个集合;
nextMember += skip
nextMember %= prime
skip的值要比集合元素个数大得多,因此选择的值好像是随机跳跃一样

直接上代码吧

//PrimeSearch.h
#pragma once
class PrimeSearch
{
    static int prime_array[];

    int skip;
    int currentPosition;
    int maxElements;
    int *currentPrime;
    int searches;

public:
    PrimeSearch(int elements);
    int GetNext(bool restart = false);
    bool Done() { return (searches == *currentPrime); }
    void Restart() { currentPosition = 0; searches = 0; }
};
//PrimeSearch.cpp
#include "PrimeSearch.h"
#include <stdlib.h>
#include <assert.h>

//#define GCC_ASSERT(a,b) assert(a);
/////////////////////////////////////////////////////////////////////////////
// DEBUG info
/////////////////////////////////////////////////////////////////////////////

#define max(a,b)            (((a) > (b)) ? (a) : (b))

int PrimeSearch::prime_array[] =
{
    2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
    53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 
    109, 113, 127, 131, 137, 139, 149,  151, 157, 163, 167, 
    173, 179, 181, 191, 193, 197, 199,  211, 223, 227, 229, 
    233, 239, 241,  251, 257, 263, 269, 271, 277, 281, 283, 
    293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 
    367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 
    433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 
    499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 
    577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 
    643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 
    719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 
    797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 
    863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 
    947, 953, 967, 971, 977, 983, 991, 997,

    // after 1000, for space efficiency reasons, 
    // we choose to include fewer prime numbers the bigger the number get.

    1009, 1051, 1103, 1151, 1201, 1259, 1301, 1361, 1409, 1451,
    1511, 1553, 1601, 1657, 1709, 1753, 1801, 1861, 1901, 1951,
    2003, 2053, 2111, 2113, 2153, 2203, 2251,
    2309, 2351, 2411, 2459, 2503, 2551, 2557,
    2609, 2657, 2707, 2753, 2767, 2801, 2851, 2903, 2953,
    3001, 3061, 3109, 3163, 3203, 3251, 3301, 3359, 3407, 3457,
    3511, 3557, 3607, 3659, 3701, 3761, 3803, 3851, 3907, 3967,
    4001, 4051, 4111, 4153, 4201, 4253, 4327, 4357, 4409, 4451,
    4507, 4561, 4603, 4651, 4703, 4751, 4801, 4861, 4903, 4951,

    // begin to skip even more primes

    5003, 5101, 5209, 5303, 5407, 5501, 5623, 5701, 5801, 5903,
    6007, 6101, 6211, 6301, 6421, 6521, 6607, 6701, 6803, 6907,
    7001, 7103, 7207, 7307, 7411, 7507, 7603, 7703, 7817, 7901,
    8009, 8101, 8209, 8311, 8419, 8501, 8609, 8707, 8803, 8923,
    9001, 9103, 9203, 9311, 9403, 9511, 9601, 9719, 9803, 9901,

    // and even more
    10007, 10501, 11003, 11503, 12007, 12503, 13001, 13513, 14009, 14503,
    15013, 15511, 16033, 16519, 17011, 17509, 18013, 18503, 19001, 19501,
    20011, 20507, 21001, 21503, 22003, 22501, 23003, 23509, 24001, 24509

    // if you need more - go get them yourself!!!!
    // Create a bigger array of prime numbers by using this web site: 
    // http://www.rsok.com/~jrm/printprimes.html
};


PrimeSearch::PrimeSearch(int elements)
{
    // "Can't do a PrimeSearch if you have 0 elements to search through, buddy-boy"
    assert(elements>0);

    maxElements = elements;

    int a = (rand() % 13) + 1;
    int b = (rand() % 7) + 1;
    int c = (rand() % 5) + 1;

    skip = (a * maxElements * maxElements) + (b * maxElements) + c;
    skip &= ~0xc0000000;       // 防止跳跃距离过大

    Restart();

    currentPrime = prime_array;
    int s = sizeof(prime_array) / sizeof(prime_array[0]);

    // if this GCC_ASSERT gets hit you didn't have enough prime numbers to deal with this number of 
    // elements. Go back to the web site.
    assert(prime_array[s - 1]>maxElements);

    while (*currentPrime < maxElements)
    {
        currentPrime++;
    }

    int test = skip % *currentPrime;
    if (!test)
        skip++;
}

int PrimeSearch::GetNext(bool restart)
{
    if (restart)
        Restart();

    if (Done())
        return -1;

    bool done = false;

    int nextMember = currentPosition;

    while (!done)
    {
        nextMember = nextMember + skip;
        nextMember %= *currentPrime;
        searches++;

        if (nextMember < maxElements)
        {
            currentPosition = nextMember;
            done = true;
        }
    }
    return currentPosition;
}
//main.cpp
#include <iostream>
#include "PrimeSearch.h"

int main(int argc, char *argv)
{
    int n = 10;
    PrimeSearch pSearch = PrimeSearch(n);
    while (true)
    {
        int getn = pSearch.GetNext();
        if (-1 == getn)
        {
            break;
        }
        std::cout << getn << " ";
    }
    std::cout << std::endl;
    return 0;
}

执行结果如下
执行结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值