我正在使用一些电子表格数据,我有一组具有任意界限的单元格区域。给定任何单元格,确定包含单元格的区域子集的最快方法是什么?
目前,我最好的方法是对主要排序字段为区域的起始行索引,后跟其结束行索引,起始列索引,然后结束列索引的区域进行排序。当我想基于给定的单元格进行搜索时,我将二进制搜索到第一个区域,其起始行索引位于单元格的行索引之后,然后检查所有区域,然后检查它们是否包含单元格,但这太慢了
答案 0 :(得分:1)
基于一些谷歌搜索,这是二维点封闭搜索问题或“刺伤问题”的一个例子。参见:
http://www.cs.nthu.edu.tw/~wkhon/ds/ds10/tutorial/tutorial6.pdf
这里(从第21/52页开始):
http://www.cs.brown.edu/courses/cs252/misc/slides/orthsearch.pdf
涉及的关键数据结构是分段树:
http://en.wikipedia.org/wiki/Segment_tree
对于2-D情况,看起来您可以构建包含分段树的分段树并获得O(log ^ 2(n))查询复杂度。 (我认为您当前的解决方案是O(n),因为平均而言,您只需用二分搜索排除一半区域。)
但是,你说“电子表格”,这意味着你可能有一个相对较小的领域可以使用。更重要的是,你有整数坐标。你说“最快”,这意味着你可能愿意交换空间和设置时间以加快查询速度。
你没有说出哪个电子表格,但下面的代码是一个非常低效,但是简单,蛮力的二维查找表的Excel / VBA实现,一旦设置,就有O(1 )查询复杂性:
Public Sub brutishButShort()
Dim posns(1 To 65536, 1 To 256) As Collection
Dim regions As Collection
Set regions = New Collection
Call regions.Add([q42:z99])
Call regions.Add([a1:s100])
Call regions.Add([r45])
Dim rng As Range
Dim cell As Range
Dim r As Long
Dim c As Long
For Each rng In regions
For Each cell In rng
r = cell.Row
c = cell.Column
If posns(r, c) Is Nothing Then
Set posns(r, c) = New Collection
End If
Call posns(r, c).Add(rng)
Next cell
Next rng
Dim query As Range
Set query = [r45]
If Not posns(query.Row, query.Column) Is Nothing Then
Dim result As Range
For Each result In posns(query.Row, query.Column)
Debug.Print result.address
Next result
End If
End Sub
如果您需要担心更大的网格或相对于网格较大的区域,则可以使用两个1-D查找表来节省大量空间和设置时间。但是,您有两个查找,并且需要获取两个结果集的交集。
答案 1 :(得分:0)
我认为你想确定单元格和区域的相交是否为Nothing
Sub RegionsContainingCell(rCell As Range, ParamArray vRegions() As Variant)
Dim i As Long
For i = LBound(vRegions) To UBound(vRegions)
If TypeName(vRegions(i)) = "Range" Then
If Not Intersect(rCell, vRegions(i)) Is Nothing Then
Debug.Print vRegions(i).Address
End If
End If
Next i
End Sub
Sub test()
RegionsContainingCell Range("B50"), Range("A1:Z100"), Range("C2:C10"), Range("B1:B70"), Range("A1:C30")
End Sub