单击鼠标时,Javascript在网页上获得最近的超链接

时间:2012-09-01 18:52:40

标签: javascript algorithm closest-points

我想知道什么是最好的解决方案。单击鼠标时,返回并显示网页上最近的超链接。

此示例中有3 DIV个。他们每个人都有一个超链接。还有另一个超链接(超链接D)本身没有DIV。让我们说红点是鼠标点击。

例如

我能想到的解决方案是通过执行

来遍历所有链接
    var a_list = document.getElementsByTagName("a");

然后使用距离方程c^2 = a^2 + b^2来计算距离,所以简单地

    var a_list = Array.prototype.slice.call(document.getElementsByTagName("a"))
    for( var i = 0 ; i < a_list.length; i++){
          Math.sqrt(Math.pow(mouseX - a_list[i].getBoundingClientRect().left,2) + 
                    Math.pow(mouseY - a_list[i].getBoundingClientRect().top,2))

    }

这种方法肯定需要O(N)时间复杂度,其中N是我们拥有的链接数。我们可以做得更好吗?

4 个答案:

答案 0 :(得分:2)

不可能比O(N)更快地执行此操作,因为您需要检查每个链接。

如果您多次进行此检查,我可以考虑更快的算法(例如,如果您每次鼠标移动时突出显示最近的链接);但那些一次性的启动成本比简单检查更糟糕。

这是一个O(N)算法真的很重要吗?是不是足够快?

关于算法的一些注意事项:

  • 你可以消除昂贵的平方根计算 - 你可以比较“距离平方”值,它仍然会告诉你更接近什么。如果你真的需要距离的东西,在你找到最近的链接之后,在最后取一个平方根
  • 您需要检查链接的哪个角落最接近鼠标,不要盲目使用左角。即对于X方向:
    • 如果mouseX&lt; link.left然后使用(mouseX - link.left)^ 2
    • 如果mouseX&gt; link.right然后使用(mouseX - link.right)^ 2
    • 否则使用0
    • ......和Y方向类似。
  • 您可以先计算delta_y ^ 2,然后将其与“距离最佳距离^ 2”值进行比较;如果它更大,那么就不需要计算delta_x ^ 2。根据浏览器,CPU和代码的其余部分,这可能会或可能不会使它更快。

答案 1 :(得分:2)

这看起来像nearest neighbor个问题,就像你有2个维度中的n个点的集合S和查询点q。 S中哪一点最接近q。

我认为如果你处理的不是那么多链接(少于一百个链接),那么简单的方法是最好的(你只需要一个。扫描每个链接并计算距离,并采取最小的一个但是,如果有数千或数百万个链接(几乎不会发生),那么你肯定需要将其缓存以供以后查询,这肯定会加快查询的时间。

  • 一种方式(你的方式)是获取所有链接,然后按X坐标对它们进行排序,你现在不关心Y坐标,然后在X上进行二进制搜索,你会最后得到一个链接,但可能不是最接近的链接,你仍然需要与前一个和下一个按距离进行比较(现在使用Y坐标)。例如,从您的示例中,当您在X上执行二进制搜索时,因为红色虚线(鼠标单击位置)的X坐标大于超链接D,所以它将在此之后搜索所有内容,但超链接D可能是最接近的,所以你需要考虑到。这种方法需要O(N log N)进行排序,O(N)空间和O(log N)进行查询。

  • 您也可以使用K-d Tree。它适用于少量维度(在您的情况下它只有两个维度x和y),它可以有效地搜索包含查询点p(您的鼠标点击位置)的单元格。
    施工时间O(N log N),空间O(N)和查询时间:O(n ^ 1/2 + k)

  • 我能想到的另一种方法是构建Voronoi diagram,它为最近邻查询提供有效的数据结构,最适合二维查询。
    施工时间O(N log N),空间O(N)和查询时间:O(log n)

所以几乎所有的方法都是一样的。

答案 2 :(得分:1)

如果您可以预先构建链接列表(即滚动时不滚动或重建),您可能需要查看平铺。

E.g。如果平铺因子为0.5,则会将链接归类为

  • 位于屏幕的左侧0.25
  • 在屏幕左侧0.5
  • 在屏幕左侧0.25-0.75
  • 在屏幕左侧0.5-1.0(= 0.5右侧)
  • 在屏幕左侧0.75-1.0(= 0.25右侧)

纵向也是如此。

点击一下,您只需要检查那些与点击位置重叠的图块中的链接。 如果你离最近的链接很远,这显然会给你“没有”,但这可能是你想要的。

答案 3 :(得分:1)

所以,我猜你有一个页面,并为很多不同的鼠标位置进行计算?

在这种情况下,您可以在第一次设置中创建2个列表,其中a按x排序,分别为。它左边的方向,分别是最高价值。 然后使用鼠标事件的x resp。 y坐标你可以像这样开始在这些列表中搜索 - 解释为x坐标:

a的完整列表开始,并将mouse-x与列表中间的元素左值进行比较。如果x较小,则重复但是从开头到中间元素的列表,如果x == left-value,则完成,如果x更大,则从中间到结尾重复列表。 如果x == left-value或要搜索的列表只有1或2个元素长,那么这样做会更接近两个元素。

必须为y坐标做同样的事情(并行)。

这还没有完全考虑过,但我非常肯定有这样的事情,你可以避免每次都与所有a标签进行比较。