JS中的树状数据结构允许最快的节点查找?

Posted

技术标签:

【中文标题】JS中的树状数据结构允许最快的节点查找?【英文标题】:Tree-like data structure in JS that allows for fastest node lookup? 【发布时间】:2015-06-16 17:20:02 【问题描述】:

我将如何在 JS 中创建树状数据结构,在其中,我可以访问诸如对父节点的引用、基于 id 的节点查找、访问子节点的长度(数量)、基于索引等内容查找等?

这基本上是我设想的 API:

var rootNode = DataStructure.getRoot();
var child1 = rootNode.addNode('child1'); //added a node with id 'child1'
child1.addNode('innerChild1');
child1.addNode('innerChild2');
rootNode.getChildById('child1') //should be same node as var child1
rootNode.getAtIndex(0) //should be same node as var child1
child1.parent() //should be rootNode
child1.getAtIndex(0) // should be node with id 'innerChild1'
child1.getAtIndex(1) // should be node with id 'innerChild2'
child1.length() //should be 2 

等等。

我理解这是一个广泛的问题,但我想知道是否有人可以推荐一种方法来解决这个问题和/或任何可能已经这样做的库?我应该只动态创建一个 XML 并使用它的本机方法吗?那会是最快的吗?

【问题讨论】:

我想你想要 jQuery? 为什么选择 jQuery?我想要一个数据结构,它不是特定于 DOM 的 看来你需要的是一个二叉搜索树Check This Out getAtIndex应该对应节点的排序顺序还是添加的顺序? 您想要通过 id 全局查找还是仅在单个父节点内查找? 【参考方案1】:

您描述的数据结构可以很容易地实现如下:

var Tree = defclass(
    constructor: function (parent) 
        this.parent   = parent || null; // null for root node
        this.children = ;             // for id based lookup
        this.ids      = [];             // for index based lookup
        this.length   = 0;              // for ease of access
    ,
    addNode: function (id) 
        var children = this.children;
        if (children.hasOwnProperty(id)) throw new Error(id + " exists");
        return children[this.ids[this.length++] = id] = new Tree(this);
    ,
    getChildById: function (id) 
        var children = this.children;
        if (children.hasOwnProperty(id)) return children[id];
        throw new Error(id + " does not exist");
    ,
    getAtIndex: function (index) 
        return this.getChildById(this.ids[index]);
    
);

function defclass(prototype) 
    var constructor = prototype.constructor;
    constructor.prototype = prototype;
    return constructor;
<script>
    setTimeout(function () 
        var rootNode    = new Tree;
        var child1      = rootNode.addNode("child1");
        var innerChild1 = child1.addNode("innerChild1");
        var innerChild2 = child1.addNode("innerChild2");

        console.assert(rootNode.getChildById("child1") === child1);
        console.assert(rootNode.getAtIndex(0)          === child1);
        console.assert(child1.parent                   === rootNode);
        console.assert(child1.getAtIndex(0)            === innerChild1);
        console.assert(child1.getAtIndex(1)            === innerChild2);
        console.assert(child1.length                   === 2);

        alert("success");
    , 0);
</script>

基于 id 的查找和基于索引的查找都采用常量(即O(1))time。希望对您有所帮助。

【讨论】:

你应该将该类命名为NodeTree 将是一个完整的“文档”,例如具有树范围的 id 查找;具有对根节点的引用的结构。 @Bergi 实际上,我更多地将其视为代数数据类型data Tree = Tree parent :: Maybe Tree, children :: Map String Tree, ids :: Array Int String, length :: Int 。由于数据构造函数返回一个Tree(它也恰好是一个节点),我将它命名为Tree 嗯。我更习惯于 ADT data Tree = Emtpy | Node … ,但我想你的也有道理。【参考方案2】:

我在应用中有这样的结构。指定的 API 会使创建您想要的结构变得困难。以下是我注意到的一些事情:DataStructure 是单例,addChild 不允许您添加带有子节点的节点,并且索引是数字。下面的呢?

API

TreeNode(新)

成员:

子项(对象,以 ID 为索引) 根(树节点) 父节点(树节点) 索引(字符串) 属性(对象) _referenceCount (int) - 如果你的树由于某种原因有循环,这很有用

方法:

addChild(TreeNode:treeNode) 向父节点注册节点 按 ID 将节点添加到子节点 增加添加的 TreeNode 的引用计数 forEach(callback(TreeNode: treeNode)) removeChild(字符串:id) 从此对象中删除节点 减少指定子节点的 _referenceCount 如果 _referenceCount 为 0,则从根中删除它

树(扩展 TreeNode)(新)

成员:

_nodeMap(对象)

方法:

getNodeByID(字符串:id) 在_nodeMap中查找id,O(1)查找时间 removeNode(字符串:id) addToNodeMap(TreeNode: treeNode)

treeFactory(可选)

方法:

createFromFormatX(Object: a tree of stuff in some specific format) 树工作正常,您应该为您的特定情况创建一个工厂,帮助您将 blob 转换为您的奇特数据结构。 createFromFormatY,基本上是另一种加载器机制

潜在的不变性

这里没有什么是必然不变的。但是,您可以通过使用新的工厂方法并将上述方法中的更多私有化始终强制树的不变性。这可能是可取的,也可能是不可取的。

【讨论】:

如果您投反对票,请发表评论。这很有效,并且有 O(1) 的查找时间。 你为什么不直接写代码?它可能会为你赢得更多的赞成票。 @Sildoreth 是的,我可能会获得更多支持?虽然通常当问题像“为我实现这个东西”时,我和这里的其他人会回避实际实现整个事情,而是选择提出一个概念。我也没有时间真正创建一个解决方案并按照它的步伐运行它。我不妨为此创建一个开源库,而不仅仅是回答 *** 问题。

以上是关于JS中的树状数据结构允许最快的节点查找?的主要内容,如果未能解决你的问题,请参考以下文章

使用递归js查找树状对象(不是二叉树)的最低共同祖先

索引碎片检测和整理

D3.js的V5版本-Vue框架中使用-树状图

使用递归js在树状对象中查找最小值和最大值

使用 D3.js 的层次力图

树状数组与线段树