用于子集索引搜索的数据结构

2023-12-03

我正在研究一个时间:2019-03-17 标签:c#jqueryimplementation我正在尝试找出一种有效的算法来在整个 DOM 的子集中定位元素(例如子选择器)。目前,我正在构建 DOM 时创建常用选择器的索引:class、id 和 tag。

正如人们所期望的那样,基本数据结构是一棵树Elements其中包含IEnumerable<Element> Children and a Parent。当使用搜索整个域时,这很简单Dictonary<string,HashSet<Element>>来存储索引。

我无法理解使用索引搜索元素子集的最有效方法。我使用术语“子集”来指代链中后续选择器将针对其运行的起始集。以下是我想到的方法:

  1. 从子查询的整个 DOM 中检索匹配项,并消除不属于子集的匹配项。这需要遍历每个匹配的父级,直到找到根(并且将其消除)或找到子集的成员(并且它是子集,因此包含在内)
  2. 为每个元素单独维护索引。
  3. 为每个元素维护一组父元素(通过消除遍历使#1 更快)
  4. 为每个子查询重建整个索引。
  5. 除了主要选择器之外,只需手动搜索即可。

每种可能技术的成本很大程度上取决于所进行的具体操作。 #1 在大多数情况下可能相当不错,因为大多数情况下,当您进行子选择时,您的目标是特定元素。所需的迭代次数为结果数 * 每个元素的平均深度。

第二种方法是迄今为止最快的选择方法,但代价是存储需求随着深度呈指数级增长,并且索引维护困难。我几乎已经消除了这个。

第三种方法的内存占用相当糟糕(尽管比第二种方法好得多)——它可能是合理的,但除了存储要求之外,添加和删除元素变得更加昂贵和复杂。

第四种方法无论如何都需要遍历整个选择,因此它似乎毫无意义,因为大多数子查询只会运行一次。仅当希望重复子查询时,这才有用。 (或者,我可以在遍历子集时执行此操作 - 除非某些选择器不需要搜索整个子域,例如 ID 和位置选择器)。

第五种方法对于有限的子集来说很好,但对于占 DOM 大部分的子集来说比第一种方法要差得多。

关于如何最好地实现这一目标有什么想法或其他想法吗?考虑到正在搜索的子集的大小与 DOM 的大小,我可以通过猜测哪个更有效来混合 #1 和 #4,但这非常模糊,我宁愿找到一些通用的解决方案。现在我只使用#4(只有完整 DOM 查询使用索引),这很好,但如果你决定做类似的事情,那就太糟糕了$('body').Find('#id')

免责声明:这是早期优化。我没有需要解决的瓶颈,但作为一个学术问题我无法停止思考......

Solution

这是答案中提出的数据结构的实现。非常适合作为字典的近乎直接替代品。

interface IRangeSortedDictionary<TValue>: IDictionary<string, TValue>
{
    IEnumerable<string> GetRangeKeys(string subKey);
    IEnumerable<TValue> GetRange(string subKey);

}
public class RangeSortedDictionary<TValue> : IRangeSortedDictionary<TValue>
{
    protected SortedSet<string> Keys = new SortedSet<string>();
    protected Dictionary<string,TValue> Index = 
        new Dictionary<string,TValue>();
    public IEnumerable<string> GetRangeKeys(string subkey)
    {
        if (string.IsNullOrEmpty(subkey)) {
            yield break;
        }
        // create the next possible string match
        string lastKey = subkey.Substring(0,subkey.Length - 1) +
            Convert.ToChar(Convert.ToInt32(subkey[subkey.Length - 1]) + 1);

        foreach (var key in Keys.GetViewBetween(subkey, lastKey))
        {
            // GetViewBetween is inclusive, exclude the last key just in case
            // there's one with the next value
            if (key != lastKey)
            {
                yield return key;
            }
        }
    }

    public IEnumerable<TValue> GetRange(string subKey)
    {
        foreach (var key in GetRangeKeys(subKey))
        {
            yield return Index[key];
        }
    }
    // implement dictionary interface against internal collections
}

代码在这里:http://ideone.com/UIp9R


如果您怀疑名称冲突并不常见,那么只需走上树就可以足够快。

如果冲突很常见,那么使用擅长有序前缀搜索的数据结构(例如树)可能会更快。您的各种子集组成了前缀。然后,您的索引键将包括选择器和总路径。

对于 DOM:

<path>
  <to>
    <element id="someid" class="someclass" someattribute="1"/>
  </to>
</path>

您将拥有以下索引键:

<element>/path/to/element
#someid>/path/to/element
.someclass>/path/to/element
@someattribute>/path/to/element

现在,如果您根据前缀搜索这些键,您可以将查询限制为您想要的任何子集:

<element>           ; finds all <element>, regardless of path
.someclass>         ; finds all .someclass, regardless of path
.someclass>/path    ; finds all .someclass that exist in the subset /path
.someclass>/path/to ; finds all .someclass that exist in the subset /path/to
#id>/body           ; finds all #id that exist in the subset /body

树可以找到下界(第一个元素> =您的搜索值)O(log n),并且因为它是从那里排序的,所以您只需迭代,直到找到不再与前缀匹配的键。会非常快!

.NET 没有合适的树结构(它有 SortedDictionary 但不幸的是没有公开所需的LowerBound方法),因此您需要编写自己的方法或使用现有的第三方方法。优秀的C5通用集合库具有适合的特征树木Range方法。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

用于子集索引搜索的数据结构 的相关文章

随机推荐

  • matplotlib 条形图中的极限误差线

    我试图让误差条显示在置信区间的限制处 而不是显示在中心 我想要的是这样的 但我得到的是这样的 为了绘制条形图 我使用了这个 import pandas as pd import numpy as np import matplotlib p
  • 验证视图状态 MAC 失败错误

    尝试通过传递参数来运行报表查看器 但收到错误 验证视图状态 MAC 失败错误 ASP NET MVC 已尝试以下但没有运气 添加了机器密钥 http aspnetresources com tools machineKey 到 web co
  • Hyperledger Fabric 加密材料

    如果我们看到加密配置文件夹中基础网络 of 布料样品 我们有各种类型的各种证书材料 example com ca 0d46ccf0e9436c1bc3b6e2bf80cdb202c4943604f95c72ee0ff839d3ec30071
  • 由于名称中存在撇号而导致无效的 XPath 表达式异常

    我收到以下代码的无效 Xpath 异常 current Name current Name replace System out println current Name String xp1 page name current Name
  • 在 web.config 文件中设置重定向

    我正在尝试使用更具描述性的 URL 来重定向一些不友好的 URL 这些 URL 结尾为 aspx cid 3916每个类别名称页面的最后一位数字都不同 我希望它重定向到Category CategoryName 3916 我在web con
  • Android:如何创建“持续”通知?

    您好 我如何创建像第一个电池指示器一样的永久通知 如果您正在使用NotificationCompat Builder 您可以使用 NotificationCompat Builder mBuilder new NotificationCom
  • 从本地 html/javascript 网站发布到在线 PHP 文件

    我正在尝试做什么 从本地 html javascript 网站发布到在线 PHP 文件 Problem 当我尝试使用下面的代码时 我不断收到下面提到的错误 背景 该网站旨在本地运行 由于每个用户都可以选择使用哪个浏览器 因此我希望找到一种可
  • 将自定义计算添加到 magento 中的购物车总计和总计

    我正在网站上工作 我想在购物车总额和总计中添加 减去费用 我正在触发此事件以捕获购物车详细信息 sales order save after 在观察者中我使用此代码获得了价格 public function modifyPrice Vari
  • 使用 awk 或 sed 基于公共列合并两个 csv 文件 [重复]

    这个问题在这里已经有答案了 我有一个两个 CSV 文件 两个文件中有一个公共列 并且一个文件中有重复项 如何使用 awk 或 sed 合并两个 csv 文件 CSV 文件 1 5 1 20 user mark Type1 445566 5
  • 如何为for循环中除最后一项之外的每一项添加分隔符

    在下面的循环中 如何从循环中的latt键中删除逗号 var result These are the results jQuery each item keyterms terms function i kw for key in keyw
  • 访问 wpf c# 应用程序中其他类中 XAML 的按钮和复选框的值

    我正在开发 WPF Kinect 项目 它是 Windows Kinect 的开发人员工具包示例之一 称为 Kinect Explorer 您可以从 Kinect 开发者工具包 SDK 1 5 版下载它 在 kinectwindow xam
  • Angular:使用 Renderer2 添加 CSS 变量

    是否可以使用添加内联样式CSS变量Renderer2 我尝试了以下方法 但它不起作用 import Component OnChanges Output ViewChild Renderer2 ElementRef ViewEncapsul
  • Node CLI 工具评估字符串

    有没有办法使用 NodeJS CLI 工具来评估一串 Javascript 代码 例如 使用 Perl 将会是perl e code 使用Pythonpython c code 与红宝石ruby e code 并且使用 PHP php r
  • width:auto 对于 字段

    CSS新手问题 我想width auto for a display block元素的意思是 填充可用空间 然而对于一个
  • 从数据属性将字符串解析为对象[重复]

    这个问题在这里已经有答案了 我在使用 jQuery 验证插件时遇到了很多麻烦 解决这个问题的唯一方法是使用 submitHandler属性并在其中做一些技巧 其中检查触发器的父级是否是字段集以及是否有data submit handler属
  • Android布局文件夹可以包含子文件夹吗?

    现在 我将每个 XML 布局文件存储在 res layout 文件夹中 因此管理小型项目是可行且简单的 但是当存在大型且繁重的项目时 则应该有一个层次结构和布局文件夹内需要的子文件夹 for e g layout layout person
  • 意外的括号“[” - PHP [重复]

    这个问题在这里已经有答案了 我正在为我的小应用程序团队的 Java 代码编写一个小型存储库 但我的代码中到处都是这个错误 base explode class 0 仅此问题出现one每次都一行代码 据我所知 上面是正确的PHP语法 那么这是
  • 使用 SentiWordNet 获取不正确的分数

    我正在使用 SentiWordNet 进行一些情感分析 我参考了这里的帖子如何使用 SentiWordNet 然而 尽管尝试了各种输入 我还是得到了 0 0 分 我在这里做错了什么吗 谢谢 import java io BufferedRe
  • 使用 Boost 库的 CMake Windows 10 库未正确找到

    像许多其他人一样 我在 Windows 上使用 boost 库时遇到问题 在 Ubuntu 16 04 上 它与 libboost all dev 配合得很好 但在 Windows 上我遇到了很多问题 我尝试构建一个 cryptonote
  • 用于子集索引搜索的数据结构

    我正在研究一个时间 2019 03 17 标签 c jqueryimplementation我正在尝试找出一种有效的算法来在整个 DOM 的子集中定位元素 例如子选择器 目前 我正在构建 DOM 时创建常用选择器的索引 class id 和