Correctness of algorithm for generating a random list of numbers from 1 to n
给出一个函数Random(x, y),该函数返回x和y(包括)之间的随机数。设计一种算法,以打印从1到n的unique_random_numbers列表。
列表中必须有n个数字,每个数字只能出现一次。
例如
1 2
| PrintRandomList(1, 5) can print -> 2, 5, 1, 4, 3
PrintRandomList(1, 6) can print -> 4, 1, 6, 3, 2, 5 |
我已经能够提出一种算法,但是无法证明它会生成一个真正的随机列表(假设Random(x, y)会生成真正的随机数)。
1 2 3 4 5 6 7 8
| void PrintRandomList(int a, int b) {
if(a<=b) {
int pivot = Random(a, b);
printf("%d", pivot);
PrintRandomList(a, pivot-1);
PrintRandomList(pivot+1, b);
}
} |
我的问题:算法正确吗?如果是,那么我们可以证明算法的正确性吗?
如果此算法正确,那么我们也可以使用它来对数组进行混洗,而不是使用Knuth混洗算法。
- 尝试多次在同一输入上运行算法。
-
@devull:没有任何"证明" ...
-
不难看出它是不正确的。它永远不会生成像2、3、1这样的序列
-
正确100%。您需要数学证明。我没有。我的数学表达不好。并且有很多方法可以使数组杂散。
-
也许我缺少了一些东西,但对我来说似乎很明显它不会生成随机列表。它将生成一个列表,其中包含第一个随机元素,然后是该元素下方的所有元素,然后是该元素上方的所有元素。在两个"下面"和"上面"部分中,将应用相同的模式,但是在给定PrintRandomList(1,3)的情况下,它永远不会生成2,3,1。
-
@Henry在此算法中,我首先打印枢轴,然后打印左半部分而不是右半部分。如果我随机决定先走一半(左或右),那么算法正确吗?
-
这将是一个无重复的洗牌数字。但是所有可能的改组排列不会有相同的机会出现。
-
@亨利:仅仅因为它不能生成每个可能的序列并不意味着它是不正确的。实际上,有人可能会说总是返回1,2,3,4,5,6也是"正确的",只是不同可能序列之间的概率并不是很好地分布;-)
-
您将始终生成一个真正的随机数,然后是一个较低的数字,再是一个较高的数字...这不是随机的
-
@Sebastian OP提到"无法证明它将生成真正的随机列表",这意味着可以生成所有可能的序列。
-
我有一个好主意。如果您希望所有排列都有相同的机会出现。并生成一个随机数0或1来决定首先运行两个语句中的哪一个。 PrintRandomList(a,枢轴1);或PrintRandomList(pivot 1,b); :)
-
如果他添加我的建议,它将产生@Henry。检查。
-
@hasan然后还有其他反例,一个是3、2、4、1
-
一种简单的方法:生成数字1到n并随机播放。
证明该算法是否有效的根本问题的技巧是,您必须证明每个结果都是同等可能的。正如其他人指出的,这里不是这种情况。
如果您找到任何无法到达或什至不太可能到达的序列,那么您就知道该算法是不公平的。这个论点的反证证明是。
- 在此算法中,我首先打印枢轴,而不是向左打印,而向右打印。如果我随机决定先走一半(左或右),那么算法正确吗?
-
@AbhinavChauhan在上述问题中看到我的评论,否;因为有一种可预测的模式。
您的算法不正确,大多数情况下,从1到n / 2的数字将位于返回列表的前半部分(想象中,pivot大约返回n / 2)。 (不容易证明它也是不正确的^^)
您需要多想一点,但是如果您要求我们提供提示,