数组的RandomShuffle算法

试题:

random(a,b)是可以产生[a,b]之间一个随机整数的函数。请使用random(a,b)写一个算法将长度为n的整型数组随机打乱。

void random_shuffle(int a[], int n);

分析:

不考虑数组中元素是否重复,长度为n的数组,其全排列共有n!种。要做到概率上的随机打乱,打乱后的排列的概率需要是1/n!。

答案一、《算法导论》中的做法:

void random_shuffle(int a[], int n)
{
    int temp_index, temp_val;

    for (int i = 0; i < n; i++)
    {
        temp_index = random(i, n-1);

        temp_val = a[temp_index];
        a[temp_index] = a[i];
        a[i] = temp_val;
    }
} 

证明:

(证明时,使用1-n的下标,注意与实现区分)。

使用如下的循环不等式:在for循环的第k次迭代之后,对每个可能的k排列,子数组a[1,k]包含这个k排列的概率是(n-k)!/n!

 初始:当k=1时,第一个元素的概率是1/n,而循环不等式(n-1)!/n!=1/n。循环不等式成立。

 保持:假设当k=i时,循环不等式也成立。则当k=i+1时,k排列的概率=(k-1)排列的概率 * 第k个元素的概率。

((n-i)!/n!) * (1/(n-i)) = (n-i-1)!/n! = (n-(i+1))!/n!

循环不等式成立。

 终止:当k=n时,((n-(n-1))!/n!) * 1 = 1/n!

由此证明算法random_shuffle产生的数组排列是均匀随机的。

更多内容可参考《算法导论》引理5.5

答案二: VC STL中algorithm的做法:

void random_shuffle(int a[], int n)
{
    int temp_index, temp_val;

    // 注意这里i是从1开始,i=0时不需要交换
    for (int i = 1; i < n; i++)
    {
        temp_index = random(0, i);

        temp_val = a[temp_index];
        a[temp_index] = a[i];
        a[i] = temp_val;
    }
}

证明:

(证明时,使用1-n的下标,注意与实现区分)。

使用如下的循环不等式:在for循环的第k次迭代之后,对每个可能的k排列,子数组a[1,k]包含这个k排列的概率是1/k!

 初始:当k=2时,第一个元素的概率是1/2,而循环不等式1/k!=1/2。循环不等式成立。

保持:假设当k=i时,循环不等式也成立。则当k=i+1时,k排列的概率=(k-1)排列的概率 * 第k个元素的概率。

(1/i!) * (1/(i+1)) = 1/(i+1)!

循环不等式成立。

终止:当k=n时,(1/(n-1)!) * (1/n) = 1/n!

由此证明算法random_shuffle产生的数组排列是均匀随机的。

小结:

《算法导论》是本很经典的书,给出了均匀排列的证明。而vc的stl算法给出了另外一种实现。对比之下,stl的算法更工程一些,因为i是1开始,而不是从0开始,当i=0时,random(0,0)还是自己,不需要交换,stl直接省却了这一步。同样《算法导论》的实现,for循环中的i<n,也可以改为i<n-1。

数组的RandomShuffle算法

时间: 2024-10-10 23:52:41

数组的RandomShuffle算法的相关文章

数组集合删除算法

数组集合删除算法: 删除: /** * 更多资料欢迎浏览凯哥学堂官网:http://kaige123.com * @author 小沫 */ public void remove(int index){ //objs的长度如果小于0或对象值小于等于0那么抛出数组越界异常 if(objs.length<0||this.index.0){ throw new IndexOutOfBoundsException(); } if(this.index-1==index){ //当前对象的是所占长度-1等

数组集合添加算法

集合是无限存储的容器: 数组集合采用的算法是一开始先开辟好有限的空间进行存储放进来的数据. 等需要再次存放数据的时候,再去开辟一块比原来的空间多的容量之前,老的数据导入进新开辟的空间,然后再把新进来的数据放进空间里,依次这样进行开辟导入就形成了无限的容器.这就是数组集合的算法.  在java源码里面,采用的导入方式是直接调用本地系统语言来直接导入数据,这样提高了效率,一万毫秒才能完成的事情也许四千毫秒就执行完毕. 取消for循环导入使用System.arraycopy如下代码: /** * 更多

线性表(一)&mdash;&mdash;数组循环右移算法

源码:rshift.cpp #include "stdafx.h" #include <stdio.h> /************************************************************************/ /* 数组循环右移算法 */ /************************************************************************/ /* * 要求:只用一个元素大小的辅助空间

70 数组的Kmin算法和二叉搜索树的Kmin算法对比

[本文链接] http://www.cnblogs.com/hellogiser/p/kmin-of-array-vs-kmin-of-bst.html [分析] 数组的Kmin算法和二叉搜索树的Kmin算法非常类似,其本质是找序列中的第K大或者第K小的元素,可以借鉴QuickSort的思想加以实现. [Kmin_of_Array] C++ Code 1234567891011121314151617181920212223242526272829303132333435363738394041

Java学习 (七)、数组,查找算法,二分查找法,冒泡排序,选择排序,插入排序

一.常用数组查找算法 工作原理:它又称为顺序查找,在一列给定的值中进行搜索,从一端的开始逐一检查每个元素,知道找到所需元素的过程. 例1:查找指定的数在数组中出现的位置,找到返回下标,找不到返回-1 1 import java.util.Scanner; 2 public class LinearSearch{ 3 public static void main(String []argas) 4 { 5 int [] array={10,100,90,65,80,92}; 6 System.o

hiho一下 第四十八周 拓扑排序&#183;二【拓扑排序的应用 + 静态数组 + 拓扑排序算法的时间优化】

题目1 : 拓扑排序·二 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho所在学校的校园网被黑客入侵并投放了病毒.这事在校内BBS上立刻引起了大家的讨论,当然小Hi和小Ho也参与到了其中.从大家各自了解的情况中,小Hi和小Ho整理得到了以下的信息: 校园网主干是由N个节点(编号1..N)组成,这些节点之间有一些单向的网路连接.若存在一条网路连接(u,v)链接了节点u和节点v,则节点u可以向节点v发送信息,但是节点v不能通过该链接向节点u发送信息. 在刚

后缀数组之倍增算法

首先说明 :后缀数组的构建在网上有多种方法:朴素的n*n*logn,还有倍增n*logn的,还有3*n的DC3算法,当然还有DC算法.这个算法学习自林厚丛老师的<高级数据结构>,代码较长,而且常数也比较大,但是是我这种笨人可以理解的.如有人想学短而快的可以学习<罗穗骞 后缀数组 ---处理字符串的有力工具>.顺便说一下,罗大神的算法书写的的确很短小也漂亮,可惜我看不懂. 说一下学习的心路历程吧!最开始想学后缀树,道理看明的了,可是一看代码实在是太长了(可能是我找的模版不对吧).后来

BZOJ 1878 SDOI2009 HH的项链 树状数组/莫队算法

题目大意:给定一个序列.求一个区间内有多少个不同的数 正解是树状数组 将全部区间依照左端点排序 然后每次仅仅统计左端点開始的每种颜色的第一个数即可了 用树状数组维护 我写的是莫队算法 莫队明显能搞 m√m明显慢了点可是还是能接受的一个复杂度 一開始离散化数组开小了各种秒RE-- 跪了 #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algori

4. 数组和排序算法1

1. 数组的定义 一组相关变量的集合 一个数组实际上就是一连串的变量 数组中的变量必须是相同的数据类型 数组可以分为一维数组.二维数组和多维数组 例如:numbers[100]来代替直接声明100个独立变量number0,number1,....,number99 2. 一维数组 2.1 数组的声明 两种声明方式: 数据类型[] 数组名 //首选 数据类型 数组名[] //效果相同,C语言的格式,不推荐 举例: int[] myList //推荐 int myList[] //不推荐 2.2 数