Reputation: 763
I need B-Tree LNR traversal (in-order). I've found an algorithm for B-Tree traversal here. How I can implement it without recursion in iterative way? I've found this question but there is no answer and the code in the question is so unclear and seems incorrect. At least, this is not the LNR and it's not suitable for me. Also I've found a lot of example of simple binary tree traversal but I need exactly B-Tree.
I use Rust but I'll be happy to see answer in any language or pseudocode.
Upvotes: 2
Views: 1480
Reputation: 1922
Though a stack/recursion is efficient, it takes O(log n)
space. This is complex if one wants to have two or more iterators at the same time, (in the heap, at least.) An alternative is to make it take O(1)
space at the cost of time, provided one has unique entries (strictly monotonic.) In pseudo-code:
iterator { tree root; { node; height; idx; } pos; };
boolean pin(iterator it) {
if(!it.root) return false;
/* Special case: off the left. */
if(!it.pos.node) it.pos.node = it.root.node,
it.pos.height = it.root.height, it.pos.idx = 0;
/* Descend the tree. */
while(it.pos.height) it.pos.height--,
it.pos.node = it.pos.node.child[it.pos.idx], it.end.idx = 0;
if(it.end.idx < it.end.node.size) return true; /* Likely. */
if(!it->end.node->size) return false;
/* Go down the tree again and note the next. */
next.node = 0, x = it.pos.node.x[it.pos.node.size - 1];
for(s = it.root; s.height; s.node = s.node.child[a0], s.height--) {
a1 = s.node.size; a0 = 0;
while(a0 < a1) {
m = (a0 + a1) / 2;
if(x > s.node->x[m]) a0 = m + 1; else a1 = m;
}
if(a0 < s.node.size)
next.node = s.node, next.height = s.height, next.idx = a0;
}
if(!next.node) return false; /* Off the right. */
it.pos = next;
return true; /* Jumped nodes. */
}
iterator begin(tree tree) {
iterator it;
it.root = tree.root, it.pos.node = 0;
return it;
}
entry next(iterator it) {
return pin(it) ? it.pos.node[it.pos.idx++].to_entry() : null;
}
In the pin
function, it takes an out-of-bounds access to the height-zero nodes and restarts from the root. It looks up the last value returned, but keeps a record of the next-key in the the descending nodes. The minimum-height node at which it found a next-key is the logical next-key. If it didn't find any next-key, the iteration is complete. This is slower, O(n log n)
to complete the entire iteration, but may be more convenient.
Upvotes: 0
Reputation: 350232
As already mentioned in comments: if you do not want to use recursion -- which would be the way to go -- then you'll have to mimic it using a stack.
An entry on that stack would be a pair consisting of:
As an example, I'll use the following B-tree:
...and use a JSON representation of it:
{
"keys": [29],
"children": [{
"keys": [15, 21],
"children": [{
"keys": [11, 12]
}, {
"keys": [18, 20]
}, {
"keys": [23, 25, 27]
}]
}, {
"keys": [35, 42],
"children": [{
"keys": [31, 33]
}, {
"keys": [36, 39]
}, {
"keys": [45, 47, 50, 55]
}]
}]
}
Here is an implementation of an iterate
function in JavaScript, which returns an iterator over the keys in LNR order:
function * iterate(node) {
let stack = []; // stack of [node, child-index] pairs
stack.push([node, 0]);
while (stack.length > 0) {
let [node, i] = stack.pop();
if (!("children" in node)) { // bottom level has no "children" member
for (let key of node.keys) {
yield key;
}
} else if (i < node.children.length) {
if (i > 0) {
yield node.keys[i-1];
}
stack.push([node, i+1]);
stack.push([node.children[i], 0]);
}
}
}
// The example B-tree:
const btree = {"keys": [29],"children": [{"keys": [15, 21],"children": [{"keys": [11, 12]}, {"keys": [18, 20]}, {"keys": [23, 25, 27]}]}, {"keys": [35, 42],"children": [{"keys": [31, 33]}, {"keys": [36, 39]}, {"keys": [45, 47, 50, 55]}]}]};
// Consume the iterator and output
console.log(...iterate(btree));
Upvotes: 3