ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

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

[分享] If …… Then 条件判断语句 的科普帖

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2014-8-19 16:20 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖已被收录到知识树中,索引项:数据类型和基本语句
一因多果,一果多因,有因必有果,有果必有因,因果关系一一对应。
谢谢分享,赞一个!

TA的精华主题

TA的得分主题

发表于 2014-8-19 21:14 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
推荐此贴“加精”!

评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-8-28 10:57 | 显示全部楼层
If 判断优化的实例:

在QuickSort快速排序递归计算过程中,有一个重要的If判断。

未优化之前,网上流行的标准QuickSort代码是这样子的:
Sub QuickSort1(tr, l&, u&)
    Dim i&, j&, x, t
    i = l: j = u
    x = tr((l + u) \ 2)
    While i <= j
        While i < u And tr(i) < x
            i = i + 1
        Wend
        While j > l And tr(j) > x
            j = j - 1
        Wend
        If i <= j Then
            t = tr(i): tr(i) = tr(j): tr(j) = t
            i = i + 1: j = j - 1
        End If

'        If i <= j Then t = tr(i): tr(i) = tr(j): tr(j) = t: i = i + 1: j = j - 1
    Wend
    If i < u Then Call QuickSort1(tr, i, u)
    If j > l Then Call QuickSort1(tr, l, j)
End Sub

代码很简洁。
甚至可以简写为:
Sub QuickSort(tr, l&, u&)
    Dim i&, j&, x, t
    i = l: j = u: x = tr((l + u) \ 2)
    While i <= j
        While i < u And tr(i) < x: i = i + 1: Wend
        While j > l And tr(j) > x: j = j - 1: Wend
        If i <= j Then t = tr(i): tr(i) = tr(j): tr(j) = t: i = i + 1: j = j - 1
    Wend
    If i < u Then Call QuickSort(tr, i, u)
    If j > l Then Call QuickSort(tr, l, j)
End Sub

但是,注意红色部分 While 条件循环时,使用了And 双条件

我前面已经介绍过,使用And 和 Or 可以简化条件判断表达式,
在仅少数几次使用时毫无问题。

但在需要循环遍历、或者反复递归计算时,
那么把 And / Or 条件 拆分后分开处理,对代码执行效率的影响、是不可忽视的。


因此,代码可以优化、而且必须优化,以提高速度效率。

仅对红色部分的优化结果为:
Sub QuickSort2(tr, l&, u&) 'Divide & Conquer
    Dim i&, j&, x, t
    i = l: j = u
    x = tr((l + u) \ 2)
    While i <= j
        Do While i < u
            If tr(i) < x Then i = i + 1 Else Exit Do
        Loop
        Do While j > l
            If tr(j) > x Then j = j - 1 Else Exit Do
        Loop

        If i <= j Then t = tr(i): tr(i) = tr(j): tr(j) = t: i = i + 1: j = j - 1
    Wend
    If i < u Then Call QuickSort2(tr, i, u)
    If j > l Then Call QuickSort2(tr, l, j)
End Sub

把原来红色部分的While条件循环,改为Do……Loop循环,即可把两个条件拆分处理。
注意原则:把容易得到结果的退出条件(这里是 i < u 或 j > l)放在Do循环层面(外层),而里层放入If 条件判断


而粉红色部分的If结构,待会儿再优化。

…………
仅这么一改,代码执行效率提高 10-15%,这绝对不是一个可以忽略的改变。

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-8-28 11:15 | 显示全部楼层
接下来,我们来考虑蓝色部分If结构的代码优化(提高效率)

If i <= j Then
    t = tr(i): tr(i) = tr(j): tr(j) = t
    i = i + 1: j = j - 1
End If


也可以转为一句式代码:
If i <= j Then t = tr(i): tr(i) = tr(j): tr(j) = t: i = i + 1: j = j - 1


分析一下,虽然看上去很像是:
If 条件 Then
   Do
End If
的最简单结构,
但实际上条件 If i <= j Then 包含了两个比较判断:
即 If i < j Or i = j Then Do

另外,Do事件又可以细分为2组:
t = tr(i): tr(i) = tr(j): tr(j) = t 即 i 位置和 j 位置的数据交换(以后称【位置交换】)
以及 i = i + 1: j = j - 1 即 i 和 j 位置的更新(以后称【位置更新】)


稍动脑子就可以知道,如果 i = j 时,则 【位置交换】其实是不必要做的。

因此,if结构的要求可以重新分析如下:
If i < j Or i = j Then
    t = tr(i): tr(i) = tr(j): tr(j) = t '仅当 i < j 时需要执行
    i = i + 1: j = j - 1 '不论 i < j 或 i = j 都需执行
End If

…………
所以,该If结果按照两个Or关系条件  i < j Or i = j 来重新拆分如下:
If i < j Then
    t = tr(i): tr(i) = tr(j): tr(j) = t '仅当 i < j 时需要执行
    i = i + 1: j = j - 1 '不论 i < j 或 i = j 都需执行
Else
  If i = j Then
    't = tr(i): tr(i) = tr(j): tr(j) = t '仅当 i < j 时需要执行 显然此句可以省去了
    i = i + 1: j = j - 1 '不论 i < j 或 i = j 都需执行
  End If
End If

根据上述结构分析,那么当 i = j 时,不需要执行【位置交换】,只需执行【位置更新】
所以,重新出列后,显然效率可以提高。

优化后的If结构代码如下:
If i < j Then
    t = tr(i): tr(i) = tr(j): tr(j) = t
    i = i + 1: j = j - 1
Else
    If i = j Then i = i + 1: j = j - 1
End If

上述If语句改写为一句式代码为:
If i < j Then t = tr(i): tr(i) = tr(j): tr(j) = t: i = i + 1: j = j - 1 Else If i = j Then i = i + 1: j = j - 1

这么改之后,代码效率又可以提升 5-10%,呵呵。

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-8-28 11:18 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
上述If结构改写时,顺序很重要!

那么,需要根据实际情形来选择。
原则是: 出现概率高的条件放在前面。

因此,i < j 条件优先于 i = j 条件

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-8-28 11:31 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
对于最初的If条件:
If i <= j Then
    t = tr(i): tr(i) = tr(j): tr(j) = t
    i = i + 1: j = j - 1
End If

可以有以下各种变化 (都是等效的,但运算效率不同,且差异不小!)

改进-1
If i <= j Then
    If i < j Then t = tr(i): tr(i) = tr(j): tr(j) = t
    i = i + 1: j = j - 1
End If

这样做,好处是当 i = j 是可以不必做【位置交换】
但仍有问题。即 还需做一次 i < j 的判断。所以效率有所改善,但仍不足。

…………
改进-2
If i = j Then
    i = i + 1: j = j - 1
Else
    If i < j Then
        t = tr(i): tr(i) = tr(j): tr(j) = t
        i = i + 1: j = j - 1
    End If
End If

这样一来,条件判断的优化结果是正确的,但条件顺序有问题,所以效率仍不是最高。

最高的是:
改进-3
If i < j Then
    t = tr(i): tr(i) = tr(j): tr(j) = t
    i = i + 1: j = j - 1
Else
    If i = j Then i = i + 1: j = j - 1
End If

每一个语句都是充分高效的。

改写为一句式代码为:
If i < j Then t = tr(i): tr(i) = tr(j): tr(j) = t: i = i + 1: j = j - 1 Else If i = j Then i = i + 1: j = j - 1

TA的精华主题

TA的得分主题

发表于 2015-1-29 15:36 | 显示全部楼层
香川群子 发表于 2014-7-9 16:17
补充,

在Access数据库操作中更为常见的 [变量结果]=IIf([条件],[真],[伪])

亲自测试了一下,真的如此!遇到0就溢出。又学到新知识了

TA的精华主题

TA的得分主题

发表于 2015-1-30 09:54 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2015-2-10 23:57 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
真是高手中的高手

TA的精华主题

TA的得分主题

发表于 2015-2-11 10:45 | 显示全部楼层
多谢热心讲解,以前一些使用if语句的疑惑终于得到了解答
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-11-18 20:47 , Processed in 0.031914 second(s), 7 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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