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-1-29 11:31 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
test1代码中,内层检查循环时的中途退出处理以后的【状态识别方法】很重要。

今后在很多循环检查代码中,都可以这么处理。

For j = 2 To i - 1
   If i Mod j = 0 Then Exit For
Next
If j < i Then a(i) = True

原理就牵涉到For……Next循环的基本概念了。

这里顺便给大家重新科普、介绍一下:(我估计很多中级以上水平的业余爱好者都还是一知半解)

① For……Next 循环,也称【计数型循环】

标准结构为:

  For i = x To y Step s  '计数器 i 变量 从x值开始,按步长 s 递增,直至超过 y值时停止循环
    ………Process           '循环中的处理过程代码
                                 '理论上还可以任意调入其它函数和过程进行计算。
                                 '……甚至GoTo 跳出循环……但跳出循环有风险,不建议新手这么做。
    …………
    If c Then                '如果满足某个条件c则可提前终止退出循环
     ………Process          '退出前做某些处理
      Exit For                 '退出本层For循环……即不进行本行以后的代码运算,直接跳到Next以后。
    End If
   …………Other Process  '当条件退出时不执行,但不退出时能正常执行的代码

    i = i + t     '根据需要加入的计数器 i 变量的调整计算 ……通常都不加。【因此很多人不知道这个用法的】
                                    '目的是:中途改变For循环的运行次数(根据计算公式进行延迟或加速!)

  Next

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-1-29 12:04 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
For……Next循环的代码简化实例:

For i = 1 To 10
   j = j + i
Next
Msgbox j

运算结果为 j = 55 即从 +1开始累加到+10 ,Σ 1-10=55

…………
继续说明:
For i = x To y Step s  '计数器 i 变量 从x值开始,按步长 s 递增,直至超过 y值时停止循环

事实上,For循环时,有一个处理过程是后台隐藏的,大家看不见,但一定存在,且非常重要:

模拟如下:
    For i = x To y Step s '前台代码
       If i = "" Then i = x Else i = i + s
       '后台-1:如果i变量为空则 i变量初始化赋值=x,否则 i = i + s  '即按步长 s 递增

       …………Process
       If i > y Then GoTo ExitFor
       '后台-2:如果i变量>计数终止值y则退出循环,跳到循环结束后的语句处。

    Next
ExitFor '后台-3:退出循环的语句位置指针。
   
…………
这里需要补充的是:
【i、x、y、s 可以为任意数值,即包括0、负数、小数。】

【Tips】但是千万需要注意,如果i、x、y、s 中任意个使用了小数或单精度、双精度变量,
则实际终止时次数可能不是你所想象的……因为必须考虑到浮点运算造成误差所带来的影响。


【Tips】由于计数器i变量的灵活性和序列性(按步长s递增或递减)的特性,
所以 计数器i变量往往被用来直接利用而省去了序列变量。……尤其是数组循环时。


可能就是这样的原因,计算机工程师们从没有规定计数器i变量必须是正整数或只限整数。

【Tips】步长s可以是正数、或负数(当然含正负小数)
当步长s为正数时,一个可以执行的循环需要 x <= y (x=y时执行1次,x>y时不执行)

但并非x>y就是代码错误……正相反、x>y不执行循环常常被用作自动处理分歧而无需另写判断代码。

同样地、当步长s为负数时,一个可以执行的循环需要 x >= y (x=y时执行1次,x<y时不执行)
而此时,必须注意计数器i变量的值,是递减的。

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-1-29 12:13 | 显示全部楼层
本帖的主要作用,不是来看我写的代码,
而是大家一起来学习,如何有步骤地、准确高效地写代码完成任务,

以及,如何学习……
关于最简单的代码,很多人会用,且经常使用,遗憾地是却从来没有深究,
① 不知道这一段代码还有什么其它用法
② 不知道这一段代码有什么讲究、限制……即可能造成问题的地方
③ 不知道这一段代码怎么用才是最高效的。
④ 不知道这一段代码如何和其它结构的代码结合在一起,产生新的高效的功能
…………

呵呵。学无止境。……多看帮助文件自己研究,多看高手代码实例,才是学习的好方法。

但最关键的是,需要自己思考和实践。

本论坛最近我注意到的个人,是aoe1981……虽然不是每天如此,但经常会对某些问题做自己的、执着的研究改进。

当然这里高手很多的,高手是怎么成为高手的,这个就是之前的用功了。呵呵。


评分

2

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-1-29 12:28 | 显示全部楼层
回到前面的问题:

【内层检查循环时的中途退出处理以后的状态识别方法。】

其实还有一种最简单的思路,可以增加一个状态变量使用:

Dim IsSumFlag As Boolean '定义是否合数的状态变量 为布尔类型

IsSumFlag = False '该【是否合数】变量初始化 记住初始化很重要!
For j = 2 To i - 1
   If i Mod j = 0 Then IsSumFlag = True: Exit For '退出前【是否合数】变量赋值=True
Next
If IsSumFlag Then a(i) = True  '根据此变量结果操作

或直接 a(i) = IsSumFlag


虽然这么做也很好,但显然有差别:
① 必须增加1个变量 (原来的做法可直接利用内层循环计数器变量 j ) 除非取了个好名字,否则增加了困难。
② 该变量必须每次都要初始化(在合适的地方进行初始化很重要,这增加了代码管理调试的困难)
③ 该变量利用率不高……或许影响不大,但仍需注意养成好习惯。


【Tips】虽然If判断有时候很快几乎不消耗多少时间,但当进行大数据大量反复循环时,仍会成为影响速度效率的一个因素,因此平时必须养成好习惯,尽量控制或减少If判断语句的使用。


关于If判断语句的代码结构,请去看下面这个专门普及帖子:
If …… Then 条件判断语句 的科普帖
http://club.excelhome.net/thread-1136095-1-1.html

评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2015-1-29 13:19 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
姐姐好牛逼........

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-1-29 14:20 | 显示全部楼层
本帖最后由 香川群子 于 2015-1-29 14:35 编辑

补充:

For……Next循环,最后 Next 后面可以跟随注明 计数器变量名称,如:

For i = 1 To 10
  For j = 1 To 10
   For k = 1 To 10
      s = s + 1
   Next k
  Next j
Next i

这样做有几个好处:
① 循环结构语句很多几十行、甚至几百行时,便于跟踪确认(另一个做法是依靠代码缩进的规范格式、或加以注释)

② i、j、k名称和实际位置不符合时(循环层嵌套行位置错误时)代码无法编译通过。

例如:
For i = 1 To 10
      For j = 1 To 10
       For k = 1 To 10
          s = s + 1
       Next j
      Next k
    Next i

这里 j和k位置颠倒了。

或者
For i = 1 To 10
      For j = 1 To 10
       For k = 1 To 10
          s = s + 1
       Next j
      Next j
    Next i

这里 j重复了……或者说k缺失了。



然而,这么做虽然似乎是个好方法……尤其是对新手来说。
但我根据自己的经验,采取的做法却是:
一开始就不再Next 后面写任何计数器变量名称。
而是正确地写出循环代码结构,这以后编译器就无需检查计数器变量名称是否匹配的问题了。


这么做其实也不难。
即,当我需要引入一层For……Next循环时,
我一定是直接写好下面两句:
For i = 1 To 10


Next


然后再修改第一句的起始值,以及在循环结构中间写入、编辑其它代码。


这样就永远不会错的。


类似的,我在写If……Then结构时,也习惯先写上:
If x Then


End If


然后再在里面编辑。


即,我的习惯是:写代码一开始就要保证结构完整、位置正确。以后再修改、调整参数则一点也不难。












TA的精华主题

TA的得分主题

 楼主| 发表于 2015-1-29 14:41 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 香川群子 于 2015-1-30 17:40 编辑

补充:

另外一种For……Next 多层嵌套循环结构时,(组合或排列算法时常用)

微软工程师允许我们对Next语句进行简化(如果不影响运行要求时。)

即,上例可写作:
Sub test()
    For i = 1 To 10
      For j = 1 To 10
       For k = 1 To 10
          s = s + 1    'Next i, j, k '方向反錯誤(最外层变量 i 放在第1个是错误的!)
    Next k, j, i  '变量从内到外排列才是正解!(最内层变量k放第1个、最外层变量 i 要在最后)
    MsgBox s
End Sub

在这里,Next语句可在最后合并为一句,并把各层次的循环计数器变量名称,以逗号分隔写在一起。

【注意】正确的顺序只有一种: 最外层(最开始)的变量 i 也要写在最外面(最右侧最后1个),而最内层(最后的)变量 k 要写在第1个(左侧第1个)
(即按代码从上到下顺序对应为从右到左的反过来的顺序),且不能缺失
  Next k, j, i是正确的
Next i, j, k  或 Next k, j, j 或 Next j, i, k 等都是错误的。

即,Next k, j, i  '这样的顺序时,排在外面最后的那个循环变量先执行。


可以这么理解:
   For i = 1 To 10
      For j = 1 To 10
        For k = 1 To 10
          s = s + 1
        Next k
      Next j
    Next i


最后的Next部分按从上到下顺序合并:
        Next k
      Next j
    Next i
自然就成为 Next k, Next j, Next i 的顺序

省去中间红色部分的Next,就成为了: Next k, j, i


呵呵。










点评

这个还真不曾注意到的,以为从左至右应该是从里到外层的……  发表于 2015-1-30 16:02

评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-1-29 14:54 | 显示全部楼层
关于For……Next循环中【计数器变量】(或称为【循环变量】)的名称:

一、通常计数器变量是整数,因此习惯用 i、j、k
二、也可以用a、b、c、d、e、f
三、如果较多则可以用字母+数字的方法来命名同一类型的循环变量,如:
     i1、i2、i3、i4、i5、……j1、j2、j3、j4、……k1、k2、k3、

四、含有较为明显含义的英文名称变量,如:
    For myRowCount = StartRow To EndRow

   Next

这样的命名方法,尤其在较为正规的编程爱好者以及习惯于在外企工作英文底子好、甚至平时一直使用洋文的人中间流行。

缺点是:
有时候一个很简单的循环变量,别这样的复杂命名搞得无法直接反应……
经常需要在脑子中转一下,这个叫做myRowCount的变量,是什么时候、在哪里产生的、如何赋值的,
在当前的代码句子中如何起作用……

但如果前面直接写了For i = 1 To EndRow
然后就使用的话,反而看到 i 就会马上反应过来这是这一层循环中的循环变量、是作为行位置参数在循环递增的。

…………
呵呵,因此,在这个问题上面有些见仁见智了。


点评

“经常需要在脑子中转一下,这个叫做myRowCount的变量,是什么时候、在哪里产生的、如何赋值的”    呵呵,说到心坎上了……  发表于 2015-1-30 16:05

TA的精华主题

TA的得分主题

发表于 2015-1-29 14:56 | 显示全部楼层

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-1-29 15:08 | 显示全部楼层
关于For循环,大致就先介绍到这里。新手有疑问不懂,可以提问。

下面接着进入本帖的数学问题:【求<n的所有素数的集合。】

我们注意到,test1代码能够正确地完成任务,但事实上效率很低。
所以,需要改进、提速。

一般说,仅仅靠代码语句的调整,变量类型的准确定义,是起不到明显的作用的。
因此,解决问题就需要有针对性的算法改进。

好的算法呢,一般说是满足:
① 精确利用了问题中数据和规则的特点、以便简化、减少计算量。
② 在必要的计算过程中,尽量把相同类型的计算需求合并或平行处理。
③ 根据实际,提前做好数据整理(预处理或数据类型转换)……这个虽然在代码中排在最开始,
   但往往会在代码开发的后期,在对问题有了更深的了解之后,才会知道应该或必须采取什么手段来处理。
   这个有句成语,叫做:【磨刀不误砍柴工】
④ 把需要在前后过程中反复使用的中间数据、存入变量或存入字典、数组中,以便反复高效地引用。
   这个和上面②、③的做法需要结合在一起。好的顺序安排,可以事半功倍。

⑤ 最后的一个技巧,尽量减少资源的占用。有些定义过的数组或变量,可以反复使用(数据类型相同或不受影响时)

这么做,好处就是高效,但如果是编写正规的大型程序,则往往不建议这么做……
会严重影响代码的可读性、以及对其他人的学习或维护产生难度。



点评

看来,有时候一个变量还是“身兼一职”的好,似乎是便于明确变量的作用定位……这个习惯又是需要辩证对待的啊……  发表于 2015-1-30 16:09
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-3-29 14:08 , Processed in 0.062608 second(s), 15 queries , Gzip On, Redis On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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