免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: win_hate
打印 上一主题 下一主题

[ML][练习] 生成排列 [复制链接]

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
21 [报告]
发表于 2008-12-02 09:47 |只看该作者
原帖由 starfuck 于 2008-12-2 00:06 发表
我倒奇怪了,占空间的方式能撑到n!多大还不死的

应该是 n 多大。n 和 n! 的数量级是不能同日而语的。

论坛徽章:
0
22 [报告]
发表于 2008-12-03 10:43 |只看该作者
原帖由 starfuck 于 2008-12-2 00:06 发表
我倒奇怪了,占空间的方式能撑到n!多大还不死的


如果在华丽地跳出来之前,能先看一看大家的讨论,就不会提这样的问题了。

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
23 [报告]
发表于 2008-12-03 11:22 |只看该作者
原帖由 win_hate 于 2008-12-3 10:43 发表


如果在华丽地跳出来之前,能先看一看大家的讨论,就不会提这样的问题了。

论坛徽章:
0
24 [报告]
发表于 2008-12-03 19:01 |只看该作者
本帖最后由 starfuck 于 2019-11-26 23:56 编辑












论坛徽章:
0
25 [报告]
发表于 2008-12-03 19:50 |只看该作者
原帖由 starfuck 于 2008-12-3 19:01 发表
移来移去取1000000个早死了,别说求n!了


我们来比较一下:

你的代码,不带输出的,公平吧?


  1. def factorial(n):
  2.     return reduce(lambda x, y: x*y, xrange(1, n+1), 1)

  3. def nth_permutation(elements, n):
  4.     for i in reversed(xrange(len(elements))):
  5.         x, n = divmod(n, factorial(i))
  6.         yield elements.pop(x)

  7. list(nth_permutation(range(1000), 0))
复制代码



  1. zxl@VIKI:~/src$ time python 1.py

  2. real    0m1.198s
  3. user    0m1.064s
  4. sys     0m0.024s
复制代码


注意你这里是1000 个数的排列,取第 0 个。如果是 10000 个数,我这里等了一分钟没出来。

我的代码:


  1. fun upto 0 = []
  2.   | upto n = n:: upto (n-1)

  3. fun nextperm (x::xs) =
  4.     let fun next (r::rs, y::ys) =
  5.             if r<=y then next(y::r::rs, ys)
  6.             else let fun swap [x] = y::x::ys
  7.                        | swap (x1::x2::xs) =
  8.                          if y<x2 then x1::swap (x2::xs)
  9.                          else (y::x2::xs)@(x1::ys)
  10.                  in swap (r::rs) end
  11.             | next (r, []) = r
  12.     in next ([x], xs) end;

  13. val x = upto 10000;

  14. fun repeat 1 = nextperm
  15.   | repeat n = nextperm o repeat (n-1);

  16. (repeat 10000) x;
  17. quit();
复制代码


一万个数的排列,取第一万零一个,带部分输出的。


  1. time mosml 1.sml

  2. real        0m0.113s
  3. user        0m0.056s
  4. sys        0m0.016s
复制代码

论坛徽章:
0
26 [报告]
发表于 2008-12-04 00:27 |只看该作者
本帖最后由 starfuck 于 2019-11-26 23:56 编辑












论坛徽章:
0
27 [报告]
发表于 2008-12-04 10:31 |只看该作者
原帖由 starfuck 于 2008-12-4 00:27 发表
我写的很清楚,阶乘可以避免重复计算,你看不见吗?


def factorials(n):
    v = 1
    yield v
    for i in xrange(1, n):
        v *= i
        yield v

def nth_permutation(elements, n):
...


如果你真的看得见,就会知道这个比较不公平。而且从一开始就不公平。

关键在于,nextperm 是通过一个排列计算另一个排列,所以在计算第 200000 个排列时,我的已经算出了 200000 个排列。你的只算了一个啊!

要公平比较,你就得用一个循环,计算从 1~200000 的全部排列.

你说的那个内存溢出是解释器造成的, mosml 目前还是个玩具。ML 的标准解释器是 smlnj,我们来看一下


  1. def factorials(n):
  2.     v = 1
  3.     yield v
  4.     for i in xrange(1, n):
  5.         v *= i
  6.         yield v

  7. def nth_permutation(elements, n):
  8.     f = list(factorials(len(elements)))
  9.     while len(elements):
  10.         x, n = divmod(n, f.pop())
  11.         yield elements.pop(x)

  12. #print list(nth_permutation(range(10000), 10**7878))
  13. print list(nth_permutation(range(10000), 200000))
复制代码


今天只有一个很旧的机器,256M 内存。不好意思。


  1. time python 1.py

  2. real        0m1.297s
  3. user        0m0.424s
  4. sys        0m0.260s
复制代码


再来看我的:


  1. time sml< 1.sml

  2. real    0m0.878s
  3. user    0m0.552s
  4. sys        0m0.128s
复制代码


我这个还可以计算大得多的排列,比如 1000000 个数的第 200000 个排列(其实是前 200001 个啦)


  1. time sml < 1.sml


  2. real        0m4.272s
  3. user        0m2.388s
  4. sys        0m0.412s
复制代码

[ 本帖最后由 win_hate 于 2008-12-4 10:37 编辑 ]

论坛徽章:
0
28 [报告]
发表于 2008-12-04 10:56 |只看该作者
本帖最后由 starfuck 于 2019-11-26 23:56 编辑












论坛徽章:
0
29 [报告]
发表于 2008-12-04 11:41 |只看该作者
我只关心算法,而不是语言。没有用 python 代码跟你的对比,是因为我不太懂 python。把 mosml 换成 smlnj 是因为你用的那个版本内存溢出了。

一开始用计算 m 个排列与你计算 1 个排列比较,是因为觉得你那陀代码太弱了。

后来你把代码改了,总不好意思要我继续让你吧。

我这段代码的目的,前面说得很清楚了。我的是 nextperm,你的是 nthperm,根本不是一回事。

我说 nthperm 在元素过多的情况下不好使,你现在又把代码改了! 你还是在计算 n! 吗?

论坛徽章:
0
30 [报告]
发表于 2008-12-04 12:02 |只看该作者
本帖最后由 starfuck 于 2019-11-26 23:56 编辑












您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP