`
kbasm
  • 浏览: 29393 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

随机排列生成算法的一些随想

阅读更多

这篇文章主要是一个闲文。如果您正在寻求一个理想的随机排列生成算法,直接阅读方法3。
另外请注意,这里所讨论的算法并不是新的。

什么是随机排列?

一个随机排列是一组位于随机位置的对象。
给定一个对象,1, 2, 3 ... n,随机排列看起来就是,
p1, p2, p3 ... pn
其中px是从原来的对象集合中选取的随机值。

随机排列对于扑克牌洗牌,随机产生益智游戏,产生随机序列,或者生成一个随机子集合集(从 n 个对象中随机选出 k 个对象),非常有用。

随机排列生成算法从天真到成熟,我的真实经验

为了解释算法,我会用一个辅助函数来产生随机数。
int random(int min, int max);
其结果是一个大于或等于 min 且小于 max 的一个随机数。
也就是说,结果是位于左闭右开区间内。

方法1,天真的方式

 

在随机位置交换两个元素。重复足够的次数。

伪代码:

array data(1..n);
for(enough iterations) {
  swap(data[random(0, n)], data[random(0, n)]);
}

 

这种方法非常直观,很简单,它真的有效,前提是有足够的迭代,比如对10个元素迭代100次。没错,它真的可以工作,我用过很多次。

但最大的问题是,迭代次数要远远高于对象数(N),因为在两次中选择相同位置的两个元素的概率是相当大的,概率为1 /(n * n)相当的高。
因此,用这种方法,我们要么得到糟糕的性能(使用非常高的迭代),要么是比较差的随机性(低迭代)。

方法2,从篮子里取小球

 

假设所有的对象都是球。我们把所有的球到一个篮子,然后从篮子里随机拿出一个球,如是重复直到篮子变空。

伪代码:

array data(1..n);
basket = new array;
for(i = 0 to N - 1) {
  basket.push(data[i]);
}
for(i = 0 to N - 1) {
  int index = random(0, basket.length);
  data[i] = basket[index];
  basket.remove(index);
}

 

这种方法也很直观,因为在现实中,彩票抽奖正是用这种方法,而且用的是真正的篮子和球。
而且这种方法性能很好,具有O(n)的时间复杂度。
理论上,其结果是能保证足够随机的,因为所有的球是从篮子里随机选择。

方法3,演进 - 在篮球里原地选择

 

第二种方法是很好的实现,而且很容易操作。但是,在计算机世界中,它有一个缺点:它需要一个额外的临时缓冲区来作为篮子。
在大多数情况下这没什么,不是个问题,但我们是否可以做得更好呢?
当然可以!我们可以在就在篮子里选择。

实际的 C++ 代码:

int random(int minValue, int maxValue)
{
    assert(minValue <= maxValue);
 
    if(minValue != maxValue) {
        return rand() % (maxValue - minValue) + minValue;
    }
    else {
        return minValue;
    }
}
 
template <typename T>
void randomPermutation(T & data, int count)
{
    using std::swap;
 
    for(int i = 0; i < count; ++i) {
        swap(data[i], data[random(i, count)]);
    }
}

 

C 版本的非模板randomPermutation(用你需要的数据类型替换 "int" ,并自行实现 swap 函数)

void randomPermutation(int * data, int count)
{
    for(int i = 0; i < count; ++i) {
        swap(&data[i], &data[random(i, count)]);
    }
}

 

上面的代码正是篮子方法的实现,不过比较隐晦。

了解原理

 

让我们假设篮子是有N个槽的长形篮子。则篮子是线性的。
那么初始篮子的样子,
1,2,3,4,5,6,...,N
现在假设我们随机选择5,那么篮子里的样子,
1,2,3,4,E,6,...,N
E表示空的槽。
接下来我们不删除E,我们把 5 之前的所有槽向后移动一个位置,并把 5 放在第一个槽里
5,1,2,3,4,6,...,N
下次如果我们选择3,我们只是移动 3 之前 5 之后的所有槽,然后把3个在那里,
5,3,1,2,4,6,...,N
重复N次

很好,是吗?我们不需要一个额外的缓冲区。但是,我们必须移动很多槽,不好玩。
如果第 C 次选择,我们只是把候选的元素与第 C 个元素交换,怎么样?
上面的迭代会进行以下变化,
1, 2, 3, 4, 5, 6, ..., N // 初始
5, 2, 3, 4, 1, 6, ..., N // 随机选择 5, 和 1 交换
5, 3, 2, 4, 1, 6, ..., N // 随机选择 3, 和 2 交换

这正是上面代码做的事情。

 

2
2
分享到:
评论
2 楼 juda 2011-05-26  
就是没看懂
1 楼 bestchenwu 2011-05-26  
好东西~
小弟我一直在找如何进行编写简单的随机数算法的办法~
谢谢分享了

相关推荐

    代码随想录算法PDF.zip

    《代码随想录》是一本深受程序员喜爱的算法学习书籍,其PDF版本为读者提供了方便的电子阅读体验。这本书主要针对准备参加编程面试或者想要提升自己算法能力的开发者,通过实例解析和实战演练,帮助读者深入理解算法...

    代码随想录算法PDF.rar

    《代码随想录》是一本深受程序员喜爱的算法学习书籍,尤其对于初学者来说,它提供了深入浅出的讲解和实战演练。这本书的核心是通过实际编程来帮助读者理解和掌握算法,提升编程技能,特别是C++语言的应用。在C++这个...

    代码随想录知识算法讲解PDF

    代码随想录贪心算法知识,非常管用

    随想出题随想出题免费版

    3. **随机组卷**:随想出题免费版具有随机组卷功能,可以根据用户设定的难度、题型比例等条件,自动生成试卷,确保每次练习的题目组合都不尽相同,增加学生的学习兴趣。 4. **答案核对**:对于客观题,软件能自动...

    代码随想录的pdf版本,需要准备秋招的小伙伴们看过来呀!

    《代码随想录》是一本深受程序员喜爱的书籍,尤其对于即将参加秋季招聘的计算机科学和技术专业的学生们来说,它是提升编程技能和算法能力的重要资源。这本书深入浅出地讲解了编程思维和各种常见算法,旨在帮助读者...

    「代码随想录」回溯算法精讲(v1.1).pdf

    由于提供的文件内容主要是对「代码随想录」回溯算法精讲pdf文件的OCR扫描文字,其中存在识别错误和遗漏,导致内容不够连贯和准确。但是,我们依然可以从描述中提炼出关键知识点。 标题“「代码随想录」回溯算法精讲...

    代码随想录 动态规划、回溯、递归、二叉树、贪心

    《代码随想录》是一本深受程序员喜爱的编程学习资料,尤其在算法领域,它提供了丰富的实例和深入的解析,帮助读者理解并掌握动态规划、回溯、递归、二叉树以及贪心等核心算法。这些算法是解决复杂计算问题的基础工具...

    编程随想博客文集 2010

    编程随想博客文集 2010

    代码随想录知识星球精华 最强⼋股⽂

    代码随想录知识星球精华(最强⼋股⽂) 这份PDF总结了 代码随想录知识星球 的全部精华内容,覆盖了⼏乎程序员学习必备的内容。 知识星球⾥很多录友拿到了⼤⼚offer,包括科班 和 ⾮科班的,⽽他们的每⽇学习总结都是...

    代码随想录-大厂八股文-面试

    代码随想录的大厂八股文面试相关知识点非常广泛,包括了编程基础、算法设计、代码组织、问题解决等多方面的知识点。为了通过面试,考察者需要具备扎实的编程基础和实践经验,能够熟练掌握多种编程语言和技术,能够写...

    代码随想录-八股文 pdf

    代码随想录-八股文 PDF 是一个涵盖了程序员学习必备的内容的知识星球精华,总结了包括 C++、Java、Go 在内的多种编程语言,数据结构和算法、操作系统、数据库、计算机网络、设计模式、Linux 等高频考点。该 PDF 由...

    编程随想博客文集 2009

    编程随想博客文集 2009

    代码随想录-大厂八股文稀有资源好几百页

    代码随想录-大厂八股文稀有资源好几百页 本资源是一个关于代码面试和算法的综合资源,涵盖了C++、Java、Go等多种编程语言,涉及到Linux操作系统和数据结构等多个领域。以下是从该资源中提取的知识点: 一、C++基础...

    软件随想录 软件随想录

    6. **软件设计原则**:书中提到了一些重要的设计原则,如单一职责原则、开闭原则、依赖倒置原则等,这些原则有助于创建可扩展和可维护的软件架构。 7. **版本控制**:在软件开发中,版本控制工具如Git的应用被高度...

    代码随想录 面试大厂必备八股文

    《代码随想录》是众多程序员面试准备的重要参考资料,尤其对于目标是大厂的开发者来说,这本书中的“面试大厂必备八股文”更是不容忽视的内容。这里的“八股文”并非传统意义上的文学形式,而是指在编程面试中经常被...

    编程随想博客匿名术文集 2009~2015

    编程随想博客匿名术文集 2009~2015

    00.代码随想录-最强八股文-第3版-无密版本.pdf

    * 代码随想录知识星球精华(最强八股文)第三版:这是一个关于编程的知识星球,涵盖了多种编程语言和技术领域,包括C++、Java、Go、数据结构和算法、操作系统、数据库、计算机网络、设计模式、Linux等等。...

    软件随想录全集

    4. **极限编程(XP)**:书中也提到了极限编程的一些实践,如结对编程、测试驱动开发(TDD)和持续集成。这些方法旨在减少错误,增强团队协作,提高软件质量。 5. **模式语言**:Martin Fowler是软件设计模式的积极推动...

    随想日语晶典2004注册器

    随想日语晶典2004注册器.exe 随想日语晶典2004注册器.exe 随想日语晶典2004注册器.exe

Global site tag (gtag.js) - Google Analytics