问题
Say I have this piece of demo data:
{
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]
}
]
}
]
}
Note, I just filled the so-called "leaf" nodes with integers to show their array positions. But they could be filled with any JavaScript objects (Arrays, objects, strings, numbers, etc.). The leaf nodes can have max 32 items, but I don't think that really matters for this question. The container nodes can only have 32 direct children as well.
How do you say getLeafContaining(tree, index)
, where it will return you the leaf which has the item at the global index
, as well as the relative index. I say "global index" because this is the index of the leaf node if you were to take all of the leaf nodes as sequential.
What I have done so far is this:
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))
It seems to be correct but I can't tell. How to you robustly implement this?
回答1:
No, it's incorrect, index <= endSize
should be index < endSize
. In the worst case this would lead to an infinite loop on an empty node.
Also a recursive solution would have been much simpler than the iterative version:
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 }
}
An alternative to the accumulating before
sum would be to decrement index
:
for (const node of nodes) {
if (index < node.size) {
return getLeafContaining(node, index);
}
index -= node.size;
}
来源:https://stackoverflow.com/questions/65553816/how-to-return-the-tree-node-by-index-when-tree-nodes-have-subtree-size