【问题标题】:Representing a tree with ordered child nodes表示具有有序子节点的树
【发布时间】:2021-02-17 02:23:22
【问题描述】:

我有一些表示为父子关系数组的树结构数据:

const tree = [{id:0, parent:-1}, 
              {id:1, parent:0}, 
              {id:2, parent:0}, 
              {id:3, parent:1}, 
              {id:4, parent:2}, 
              {id:5, parent:2}, 
              {id:6, parent:2}]

这会产生以下树:

-0
 |-1
   |-3
 |-2
   |-4
   |-5
   |-6

我想让树“可排序”,以便可以操纵节点子节点的顺序,例如节点 2 的子节点可以重新排序为 5,4,6,如下所示:

-0
 |-1
   |-3
 |-2
   |-5
   |-4
   |-6

哪种数据结构最有利于实现这一点?

我能想到的唯一两种可能性是嵌套结构:

const nested = [
  {
    id:0,
    children: [
      {
        id: 1, 
        children: [{id: 3, children:[]}]
      }, 
      {
        id:2, 
        children: [
          {
            id:4, children:[]
          }, 
          {
            id:5, children:[]
          }, 
          {
            id:6, children:[]
          }
        ]
      }
    ]
  }
]

这需要使用递归函数,它的性能似乎不如上面父子关系数组的平面结构。

或者,我可以将子订单作为数组显式存储在父子关系数组中的父项中:

const tree2 = [{id:0, parent:-1, children=[1,2]}, 
  {id:1, parent:0, children=[3]}, 
  {id:2, parent:0, children=[4,5,6]}, 
  {id:3, parent:1, children=[]}, 
  {id:4, parent:2, children=[]}, 
  {id:5, parent:2, children=[]}, 
  {id:6, parent:2, children=[]}]

但我不确定这有多正确,因为 children 数组是冗余信息。

【问题讨论】:

  • 下面有一些答案。你看过他们吗?

标签: javascript data-structures tree data-manipulation hierarchical-data


【解决方案1】:

您可以为列表中的每个“节点”添加一个序列属性:

const tree = [
  { id:0 , seq: 0, parent: -1 }, 
  { id:1 , seq: 0, parent:  0 }, 
  { id:2 , seq: 1, parent:  0 }, 
  { id:3 , seq: 0, parent:  1 }, 
  { id:4 , seq: 0, parent:  2 }, 
  { id:5 , seq: 1, parent:  2 }, 
  { id:6 , seq: 2, parent:  2 },
];

但这很笨拙。只需将数据表示为树。递归树遍历非常简单。任何递归函数都可以简单地通过显式堆栈或队列转换为迭代,即:

const tree = {
    id: 0,
    children: [
        {
            id: 1,
            children: [
                { id: 3, children: [], },
            ],
        },
        {
            id: 2,
            children: [
                { id: 4, children: [], },
                { id: 5, children: [], },
                { id: 6, children: [], },
            ],
        },
    ],
};

function *visit_recursive(tree) {

    yield *walk([], tree);
    return;

    function *walk( parents, root ) {
        // if there is no node, we're done.
        if (!root) {
            return;
        }

        // first, yield the current (root) node
        yield { path: parents, node: root };

        parents.push(root.id);
        for (const child of root.children) {
            yield *walk( parents, child );
        }
        parents.pop();

        return;
    }

}

function *visit_iterative(tree) {
    const pending = [ {path: [], node: tree } ];

    while ( pending.length > 0 ) {
        const { path, node } = pending.shift();

        yield { path, node };

        for ( const child of node.children ) {
            pending.push( {path: [...path, node.id], node:child} );
        }

    }

}

console.log('Recursive Traversal:');
for (const item of visit_recursive(tree) ) {
    const { path, node } = item;
    console.log(`${['{root}', ...path, node.id].join(' > ')}: child_count=${node.children.length}` );
}

console.log();

console.log('Iterative Traversal:');
for (const item of visit_iterative(tree) ) {
    const { path, node } = item;
    console.log(`${['{root}', ...path, node.id].join(' > ')}: child_count=${node.children.length}` );
}

运行它会给你这样的输出(为了整洁而格式化):

Recursive Traversal:

{root} > 0         : child_count=2
{root} > 0 > 1     : child_count=1
{root} > 0 > 1 > 3 : child_count=0
{root} > 0 > 2     : child_count=3
{root} > 0 > 2 > 4 : child_count=0
{root} > 0 > 2 > 5 : child_count=0
{root} > 0 > 2 > 6 : child_count=0

Iterative Traversal:

{root} > 0         : child_count=2
{root} > 0 > 1     : child_count=1
{root} > 0 > 2     : child_count=3
{root} > 0 > 1 > 3 : child_count=0
{root} > 0 > 2 > 4 : child_count=0
{root} > 0 > 2 > 5 : child_count=0
{root} > 0 > 2 > 6 : child_count=0

【讨论】:

    【解决方案2】:

    您可以保持结构不变,因为数组意味着排序顺序。虽然相对顺序与非同级条目对无关,但它确实将顺序信息提供给同级。

    什么才是最合适的数据结构取决于您需要对其执行的所有其他操作(查找、插入、删除、更新、获取最小值、迭代......)。动作类型越多,使用适当的嵌套树数据结构的优势就越多,可能具有一些自平衡功能,如搜索树往往具有(AVL、红黑、B-tree ......)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多