ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

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

[分享] 对Lookup二分法查找定位过程的模拟解析

[复制链接]

TA的精华主题

TA的得分主题

发表于 2012-3-31 17:23 | 显示全部楼层 |阅读模式
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖已被收录到知识树中,索引项:LOOKUP
经常听说,Excel中的Lookup、VLookup,甚至于字典方法,

本质上都是靠二分法来进行快速查找定位的。

即,从中间位置取值作比较,如果>比较值则向后再取中间值、如果<比较值则向前再取中间值,
然后继续比较,直到找到相同值,或查询到最小/最大位置时结束。


因为有如此做法,所以当对象数据未经按从小到大的顺序排序时,
使用Lookup查询经常会返回一个令人一下子不知来历的位置的值。

总之,二分法虽然大家都听懂了,也相信了,
但具体是一个怎样的过程,一下子很难理解。


………………
附件中,我写了一段代码,模拟了二分法的查找过程。

使用自定义函数,可以返回每一查找步骤的比较值、查询位置,直到最后结束。

按此过程在来看,应该会更容易理解二分法的做法了。



Lookup2.zip

29.92 KB, 下载次数: 510

评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-3-31 17:25 | 显示全部楼层
这个是具体的代码:
  1. Function VL(x, r, Optional k = 0)
  2. '    Exit Function
  3.     m = r.Count:    h = m + 1:  l = 0:    t = l + (h - l) \ 2: s = " |"
  4.     If IsNumeric(x) Then x = Val(x) Else x = x.Text
  5.     Do
  6.         If IsNumeric(r.Item(t)) Then y = Val(r.Item(t)) Else y = r.Item(t).Text
  7.         
  8.         If x < y Then
  9.             s = s & "<" & y & "(" & t & ") " & ChrW(8594)
  10.             If t = 1 Then VL = 1: Exit Do
  11.             h = t:       t = l + (h - l) \ 2
  12.         Else
  13.             If x = y Then
  14.                 q = t: s = s & "=" & y & "(" & t & ") " & ChrW(8594)
  15.                 For t = t + 1 To h - 1
  16.                     If IsNumeric(r.Item(t)) Then y = Val(r.Item(t)) Else y = r.Item(t).Text
  17.                     If x = y Then q = t Else Exit For
  18.                 Next
  19.                 VL = 2: Exit Do
  20.             End If
  21.             If t = h - 1 Then VL = 3: Exit Do
  22.             p = t: s = s & ">" & y & "(" & t & ") " & ChrW(8594)
  23.             l = t: t = l + (h - l) \ 2
  24.         End If
  25.     Loop
  26.    
  27.     If k = 0 Then
  28.         If VL = 1 Then
  29.             VL = "#N/A"
  30.         ElseIf VL = 2 Then
  31.             VL = x
  32.         Else
  33.             VL = y
  34.         End If
  35.     ElseIf k = 1 Then
  36.         If VL = 1 Then
  37.             VL = "#N/A"
  38.         ElseIf VL = 2 Then
  39.             VL = q
  40.         Else
  41.             VL = t
  42.         End If
  43.     Else
  44.         If VL = 1 Then
  45.             VL = "NA (1)" & s & "S #NA|1"
  46.         ElseIf VL = 2 Then
  47.             VL = x & " (" & q & ")" & s & "=" & x & "(" & q & ")" & ChrW(8594) & "=|2"
  48.         ElseIf VL = 3 Then
  49.             VL = y & " (" & t & ")" & s & ">" & y & "(" & t & ")" & ChrW(8594) & ">H|3"
  50.         End If
  51.     End If
  52. End Function
复制代码

TA的精华主题

TA的得分主题

发表于 2012-3-31 17:33 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
研究……二分法让LOOKUP很给力

TA的精华主题

TA的得分主题

发表于 2012-3-31 17:37 | 显示全部楼层
偶不同意这种说法,Lookup有精确查找和顺序查找,都是从指定位置到目标位置顺序查找的,找到第一个符合条件就退出。

TA的精华主题

TA的得分主题

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

核心代码解释:

    m = r.Count '元素总数
   t = (m +1) \ 2 '第1步查询中间位置,如9或10个元数取5,11或12个元素取6
   
    '下面Do……Loop循环,x=检查值,y=当前比较值
    Do
        If x < y Then '如果小于比较值
            If t = 1 Then VL = "#N/A" : Exit Do '如果比第1个值还小,则返回找不到错误值。
            h = t:       t = l + (h - l) \ 2 '以当前位置为最高位置,计算向下查询的中间位置
        Else
            If x = y Then '如果已经和比较值相等了
                q = t '记录当前位置
                For t = t + 1 To h - 1 '向后遍历查询比对是否还有相同值
                    If x = y Then
                       q = t '如果还相同,则更新位置
                    Else
                       Exit For '如果不相同则直接退出
                    End If
                Next
                VL = q : Exit Do '返回最后一个相同值位置
            End If
            
           '以下为大于比较值时
            If t = h - 1 Then VL = t: Exit Do '如果当前查询位置和已检查最高位置只差一个时可结束检查了。
            p = t '否则记录当前位置
            l = t: t = l + (h - l) \ 2 '计算向后查询的新的中间位置
        End If
    Loop
   

上面是主要代码过程,具体的一些细节代码,就忽略掉了。


TA的精华主题

TA的得分主题

发表于 2012-3-31 17:54 | 显示全部楼层

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-4-5 23:12 | 显示全部楼层
经典12球中有一重量不等坏球的问题。
BALL 12A.jpg
BALL 12.jpg

评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2012-4-6 09:25 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2012-5-4 18:11 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2012-10-8 12:09 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
LOOKUP用的一定不是哈希表,因为一个函数建一次哈希表很不值,
只要数据是排序好的,使用二分法并不会比哈希表慢.
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-12-4 01:28 , Processed in 0.047696 second(s), 13 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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