ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 Excel Home精品图文教程库
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
300集Office 2010微视频教程 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: 香川群子

[原创] 跟我学算法 【初级篇】:求某个整数范围内所有素数

  [复制链接]

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-2-23 23:09 | 显示全部楼层
本帖最后由 香川群子 于 2015-2-23 23:11 编辑
下标越界 发表于 2015-2-18 17:26
要搁我这写,首先会是一个test0()

补充内容 (2015-2-23 22:15):


不好意思,你的代码有bug,输出结果不正确……

应改为:
Sub test0-2() '对【下标越界】 79楼 2015-2-18 代码的修正   
    Dim i&, j&, k&, n&, a&()
    n = [a1]
  For n = 2 To 123 '加入n循环测试

    ReDim a&(1 To n)
    k = 1
    For i = 2 To n + 1
        a(k) = i
        For j = 2 To i - 1
            If i Mod j = 0 Then k = k - 1: Exit For
        Next j
        k = k + 1
    Next i
    If a(k - 1) > n Then k = k - 1 ': a(k - 1) = "" '此处改参数k即可,无需改a(k - 1)值   
    If k < 65536 Then [b:b] = "": [b1].Resize(k - 1) = Application.Transpose(a)
    '输出有效行数=k-1,而不是=k  
  Next n  'n循环测试
End Sub

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-2-23 23:17 | 显示全部楼层
本帖最后由 香川群子 于 2015-2-23 23:25 编辑
下标越界 发表于 2015-2-18 17:26
要搁我这写,首先会是一个test0()

补充内容 (2015-2-23 22:15):


对【下标越界】79楼代码的进一步修改(只是个人习惯,但运算效率变化不大因为本身就是最差的算法了):
  1. Sub test0-3()
  2.     Dim i&, j&, k&, n&, a&()
  3.     n = [a1]
  4.    
  5.     ReDim a&(n)
  6.     For i = 2 To n
  7.         a(k) = i
  8.         For j = 2 To i - 1
  9.             If i Mod j = 0 Then k = k - 1: Exit For
  10.         Next
  11.         k = k + 1
  12.     Next
  13.     If k < 65536 Then [b:b] = "": [b1].Resize(k) = Application.Transpose(a)
  14. End Sub
复制代码

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-2-23 23:28 | 显示全部楼层
下标越界 发表于 2015-2-23 22:22
按群子老师的test9对1千2百万范围内的整数筛选出788060个素数。
想象中按照分块显示输出到excel表格中,分 ...

单元格添加底色是个费时费力的工作。没有意义。

TA的精华主题

TA的得分主题

发表于 2015-2-23 23:40 | 显示全部楼层
香川群子 发表于 2015-2-23 23:28
单元格添加底色是个费时费力的工作。没有意义。

嗯,是没意义,存在于想象中即可。
群子老师,我知道我歪楼了。

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-2-24 00:42 | 显示全部楼层
下标越界 发表于 2015-2-23 22:22
按群子老师的test9对1千2百万范围内的整数筛选出788060个素数。
想象中按照分块显示输出到excel表格中,分 ...

我的素数矩阵输出代码:

单元格不加底色时,运算和输出都很快的。
  1. Sub PrimeTable() '生成输出筛子法素数矩阵表
  2.     Dim i&, j&, k&, l&, m&, n&, r&, s&, t&, c&
  3.    
  4.     s = 120 '输入<=250的整数 作为输出正方形矩阵的边长s、如n=10、n=100、n=250
  5.     t = Int(250 / s) '计算得到2003工作表中横向展开的最多矩阵个数t
  6.     n = Val(InputBox("请输入纵向矩阵数、即" & s * s * t & "的倍数n=[1-100]", "生成输出筛子法素数矩阵表", Int(Rnd * 100 + 1)))
  7.     If n < 1 Or n > 100 Then Exit Sub Else n = n * s * s * t '纵向矩阵数n换算得到求素数最大范围n
  8.    
  9.     '以下为计算范围内素数
  10.     m = (n - 1) \ 2: ReDim a(1 To m) As Boolean
  11.     For i = 1 To Sqr(n) \ 2
  12.         If a(i) = False Then
  13.             For j = i * 3 + 1 To m Step i * 2 + 1
  14.                 a(j) = True
  15.             Next
  16.         End If
  17.     Next
  18.    
  19.     '以下为按边长s的矩阵、把各个素数转换为输出数组b要求的行列坐标
  20.     ReDim b(1 To n / s / t, 1 To s * t)
  21.     b(1, 1) = 1: b(1, 2) = 2
  22.     For i = 1 To m
  23.         If a(i) = False Then
  24.             k = i * 2
  25.             l = k - Int(k / s / s) * s * s
  26.             r = Int(l / s) + 1 + Int(k / s / s / t) * s
  27.             c = l Mod s + 1 + (Int(k / s / s) Mod t) * s
  28.             b(r, c) = k + 1
  29.         End If
  30.     Next
  31.    
  32.     Cells = "" '清空
  33.     [b2].Resize(n / s / t, s * t) = b '输出
  34. End Sub
复制代码

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-2-24 01:23 | 显示全部楼层
但是,如果要一下子输出4800行*250列=120万个单元格,这个只有看硬件配置了。差一点的电脑只有死机。

TA的精华主题

TA的得分主题

发表于 2015-2-24 11:13 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
好东西,楼楼多写点东西吧。

TA的精华主题

TA的得分主题

发表于 2015-2-24 21:51 | 显示全部楼层
本帖最后由 下标越界 于 2015-2-24 23:21 编辑
香川群子 发表于 2015-2-24 00:42
我的素数矩阵输出代码:

单元格不加底色时,运算和输出都很快的。

仔细阅读了一下群子老师的输出代码,仅用一层循环实现了方阵输出:
For i = 1 To m
        If a(i) = False Then
            k = i * 2
            l = k - Int(k / s / s) * s * s                      ‘计算当前素数在当前构造方阵里的序号(范围1到 s X s)
            r = Int(l / s) + 1 + Int(k / s / s / t) * s      ‘计算行号: Int(l / s) + 1计算当前素数在当前构造方阵里所在行数,Int(k / s / s / t) * s 计算当前构造方阵“上方”紧邻的行数。两者加起来就是当前素数在“区域”中的所在行数。
            c = l Mod s + 1 + (Int(k / s / s) Mod t) * s     ‘计算列号: l Mod s + 1计算当前素数在当前构造方阵里所在的列数,(Int(k / s / s) Mod t) * s 计算当前构造方阵前面“Int(k / s / s)”个完整方阵中经过横向展开后余下“边角料”方阵的个数,由于每个方阵为s X s,所以当前构造方阵前面“(Int(k / s / s) Mod t) ”个“边角料”方阵占用了“(Int(k / s / s) Mod t) * s ”列。于是当前素数在“区域”中的列数是两者之和。
            b(r, c) = k + 1      '将素数存入二维数组  
        End If
    Next

TA的精华主题

TA的得分主题

发表于 2015-2-24 22:11 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 下标越界 于 2015-2-24 22:16 编辑

      用群子的代码测试输出1千2百万范围内的素数,发现速度很快,仅几秒钟,而本人在80楼测试的输出时间达到近80秒。两相比较一下就看出:群子使用了二维数组整体输出到excel表格中,大大提升了输出速度,节约了大量时间。于是我把80楼的代码稍稍改动了一下:
  1. Sub test9()

  2.     Dim t1, t2, r11, c11, tab1, arr()

  3.     Dim i&, j&, k&, m&, n&, tim1, tim2
  4.     n = [a1]
  5.    
  6.       tim1 = Timer
  7.     m = (n - 1) \ 2: ReDim a(1 To m) As Boolean
  8.     For i = 1 To Sqr(n) \ 2
  9.         If a(i) = False Then
  10.             For j = i * 3 + 1 To m Step i * 2 + 1
  11.                 a(j) = True
  12.             Next
  13.         End If
  14.     Next
  15.    
  16.     nSize = Array(1, 1, 0.5, 0.17, 0.125, 0.1, 0.08, 0.067, 0.058, 0.055)
  17.     k = n * nSize(Log(n) / Log(10))
  18.     ReDim b&(1 To k): b(1) = 1: b(2) = 2: k = 2
  19.     For i = 1 To m
  20.         If a(i) = False Then k = k + 1: b(k) = i * 2 + 1
  21.     Next
  22.    
  23.     tim2 = Timer

  24.     ReDim Preserve b&(1 To k)
  25.     '[a9] = k: If k < 65536 Then [b:b] = "": [b1].Resize(k) = Application.Transpose(b)
  26.   Cells.Clear
  27.    t1 = Timer
  28.    
  29.         ' r1 = Int((k - 1) / 100) + 1
  30.          r11 = Int((k - 1) / 2500) + 1
  31.         
  32.    ReDim arr(1 To r11 * 10, 1 To 250)
  33.         
  34. On Error Resume Next
  35.         For i = 1 To r11
  36.           For j = 1 To 25
  37.             Set tab1 = Cells(1 + (i - 1) * 10 + 1, 1 + (j - 1) * 10 + 1)
  38.             Range(tab1, tab1.Offset(9, 9)).Interior.Color = RGB(255 * Round(Rnd), 255 * Round(Rnd), 255 * Round(Rnd)) '(1 + (-1) ^ (j + 1)) / 2)
  39.             For o = 1 To 100
  40.              ' Cells(Int((o - 1) / 10) + 1 + (i - 1) * 10 + 1, (o - 1) Mod 10 + 1 + (j - 1) * 10 + 1) = b((i - 1) * 2500 + (j - 1) * 100 + o)
  41.                arr(Int((o - 1) / 10) + 1 + (i - 1) * 10, (o - 1) Mod 10 + 1 + (j - 1) * 10) = b((i - 1) * 2500 + (j - 1) * 100 + o)
  42.         Next o, j, i
  43.         
  44.      
  45.     [b2].Resize(r11 * 10, 250) = arr '输出
  46.    ' MsgBox arr(2, 2)
  47.    t2 = Timer
  48.    
  49.    Cells(1, 2) = "test9范围" & n & "耗时" & tim2 - tim1 & "秒"
  50.    Cells(1, 3) = "输出耗时" & t2 - t1 & "秒"
  51.    Cells(1, 4) = k & "个素数"
  52.    
  53. End Sub
复制代码
运行结果如图:

输出耗时缩短

输出耗时缩短



        综合以上,算不算是一个”空间换时间“的例子呢?

C:\Users\wen\Pictures\输出耗时缩短

TA的精华主题

TA的得分主题

发表于 2015-2-24 23:44 | 显示全部楼层
从1楼至20楼受益匪浅。本人数学不及格,余下楼层头大,跑马观花。
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-4-28 18:10 , Processed in 0.034108 second(s), 9 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表