我想知道什么是最好的解决方案。单击鼠标时,返回并显示网页上最近的超链接。
此示例中有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是我们拥有的链接数。我们可以做得更好吗?
答案 0 :(得分:2)
不可能比O(N)更快地执行此操作,因为您需要检查每个链接。
如果您多次进行此检查,我可以考虑更快的算法(例如,如果您每次鼠标移动时突出显示最近的链接);但那些一次性的启动成本比简单检查更糟糕。
这是一个O(N)算法真的很重要吗?是不是足够快?
关于算法的一些注意事项:
答案 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,则会将链接归类为
纵向也是如此。
点击一下,您只需要检查那些与点击位置重叠的图块中的链接。 如果你离最近的链接很远,这显然会给你“没有”,但这可能是你想要的。
答案 3 :(得分:1)
所以,我猜你有一个页面,并为很多不同的鼠标位置进行计算?
在这种情况下,您可以在第一次设置中创建2个列表,其中a
按x排序,分别为。它左边的方向,分别是最高价值。
然后使用鼠标事件的x resp。 y坐标你可以像这样开始在这些列表中搜索 - 解释为x坐标:
从a
的完整列表开始,并将mouse-x与列表中间的元素左值进行比较。如果x较小,则重复但是从开头到中间元素的列表,如果x == left-value,则完成,如果x更大,则从中间到结尾重复列表。
如果x == left-value或要搜索的列表只有1或2个元素长,那么这样做会更接近两个元素。
必须为y坐标做同样的事情(并行)。
这还没有完全考虑过,但我非常肯定有这样的事情,你可以避免每次都与所有a
标签进行比较。