【问题标题】:How to return the tree node by index when tree nodes have subtree size?当树节点具有子树大小时,如何按索引返回树节点?
【发布时间】:2021-01-03 19:09:54
【问题描述】:

假设我有这段演示数据:

{
  size: 100,
  type: 'container',
  list: [
    {
      size: 30,
      type: 'container',
      list: [
        {
          size: 10,
          type: 'leaf',
          list: [1,2,3,4,5,6,7,8,9,10]
        },
        {
          size: 15,
          type: 'leaf',
          list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
        },
        {
          size: 25,
          type: 'leaf',
          list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]
        }
      ]
    },
    {
      size: 50,
      type: 'container',
      list: [
        {
          size: 20,
          type: 'leaf',
          list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
        },
        {
          size: 25,
          type: 'leaf',
          list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]
        },
        {
          size: 25,
          type: 'leaf',
          list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]
        }
        ,
        {
          size: 30,
          type: 'leaf',
          list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]
        }
      ]
    },
    {
      size: 20,
      type: 'container',
      list: [
        {
          size: 5,
          type: 'leaf',
          list: [1,2,3,4,5]
        },
        {
          size: 15,
          type: 'leaf',
          list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
        }
      ]
    }
  ]
}

注意,我只是用整数填充了所谓的“叶”节点以显示它们的数组位置。但它们可以填充任何 JavaScript 对象(数组、对象、字符串、数字等)。叶节点最多可以有 32 个项目,但我认为这对这个问题并不重要。容器节点也只能有 32 个直接子节点。

getLeafContaining(tree, index) 怎么说,它会返回在全局 index 处具有项目的叶子以及相对索引。我说“全局索引”是因为如果您要将所有叶节点视为连续的,这是叶节点的索引。

到目前为止我所做的是:

const getLeafContaining = (tree, index) => {
  if (index > tree.size - 1) {
    return { node: null, index: -1 }
  }

  let nodes = [tree]
  let startSize = 0
  a:
  while (true) {
    b:
    for (let i = 0, n = nodes.length; i < n; i++) {
      let node = nodes[i]
      let endSize = startSize + node.size
      if (startSize <= index && index <= endSize) {
        if (node.type == 'container') {
          nodes = node.list
          break b
        } else {
          let relativeIndex = index - startSize
          return { node, index: relativeIndex }
        }
      } else {
        startSize = endSize
      }
    }
  }
}

const tree = {
  size: 100,
  type: 'container',
  list: [
    {
      size: 30,
      type: 'container',
      list: [
        {
          size: 10,
          type: 'leaf',
          list: [1,2,3,4,5,6,7,8,9,10]
        },
        {
          size: 15,
          type: 'leaf',
          list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
        },
        {
          size: 25,
          type: 'leaf',
          list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]
        }
      ]
    },
    {
      size: 50,
      type: 'container',
      list: [
        {
          size: 20,
          type: 'leaf',
          list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
        },
        {
          size: 25,
          type: 'leaf',
          list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]
        },
        {
          size: 25,
          type: 'leaf',
          list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]
        }
        ,
        {
          size: 30,
          type: 'leaf',
          list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]
        }
      ]
    },
    {
      size: 20,
      type: 'container',
      list: [
        {
          size: 5,
          type: 'leaf',
          list: [1,2,3,4,5]
        },
        {
          size: 15,
          type: 'leaf',
          list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
        }
      ]
    }
  ]
}

console.log(getLeafContaining(tree, 22))

这似乎是正确的,但我不能说。您如何稳健地实现这一点?

【问题讨论】:

  • “相对索引”是什么意思?
  • 奇怪的是你没有在树上使用标准的递归方法
  • 相对索引是相对于最终叶子的索引,最多包含32项。

标签: javascript arrays search tree


【解决方案1】:

不,不正确,index &lt;= endSize 应该是 index &lt; endSize。在最坏的情况下,这会导致空节点上的无限循环。

递归解决方案也比迭代版本简单得多:

const getLeafContaining = (tree, index) => {
  if (index < tree.size) {
    if (node.type == 'leaf') {
      return { node, index };
    } else if (node.type == 'container') {
      let before = 0
      for (const node of nodes) {
        const after = before + node.size;
        if (index < after) {
          return getLeafContaining(node, index - before);
        }
        before = after;
      }
    }
  }
  return { node: null, index: -1 }
}

累积before 和的替代方法是减少index

      for (const node of nodes) {
        if (index < node.size) {
          return getLeafContaining(node, index);
        }
        index -= node.size;
      }

【讨论】:

    猜你喜欢
    • 2011-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-29
    • 1970-01-01
    • 2023-04-07
    相关资源
    最近更新 更多