function *dfs(root) {
yield root;
for (let child of root.children) {
yield *dfs(child);
}
}
function *bfsArray(root) {
let queue = [root];
do {
let node = queue.shift();
yield node;
queue.push(node.children);
} while (queue.length);
}
function *bfsLinkedList(root) {
let head = {node: root, next: null};
let tail = head;
do {
let node = head.node;
yield node;
for (let child of node.children) {
tail = tail.next = {node: child, next: null};
}
head = head.next;
} while (head !== null);
}
function makeRandomTree(depth, degree) {
let node = {
data: Math.round(Math.random() * 100),
children: []
};
if (depth !== 0)
for (let i = 0; i < degree; ++i) {
node.children.push(makeRandomTree(depth - 1, degree));
}
return node;
}
const testTree = makeRandomTree(7, 5);
for (let node of dfs(testTree)) {node.data;}
for (let node of bfsArray(testTree)) {node.data;}
for (let node of bfsLinkedList(testTree)) {node.data;}
--enable-precise-memory-info
flag.
Test case name | Result |
---|---|
Pre-order | |
Level-order with array | |
Level-order with linked list |
Test name | Executions per second |
---|---|
Pre-order | 20.6 Ops/sec |
Level-order with array | 100.6 Ops/sec |
Level-order with linked list | 104.8 Ops/sec |
The benchmark provided tests different tree traversal methods in JavaScript, focusing on three approaches: pre-order depth-first search (DFS), and level-order breadth-first search (BFS) using both an array and a linked list. Here's a detailed explanation of the benchmarks, their implementations, and considerations:
Pre-order (DFS):
dfs(root)
function uses a generator to yield the root node followed by recursively yielding its children. This results in a depth-first traversal where each node is processed before its children.Level-order using Array (BFS):
bfsArray(root)
function utilizes an array to manage the queue of nodes to visit. It processes nodes from the front of the queue and adds their children to the back.shift()
and push()
).Level-order using Linked List (BFS):
bfsLinkedList(root)
function defines a linked list structure to maintain the queue. Each node's children are appended to the end of the list, promoting efficient enqueueing and dequeueing.tail
management).The benchmark results show that for the current testing environment (Chrome 131 on macOS), the fastest approach was the Level-order with linked list, performing at approximately 663.09 executions per second. This suggests that for the data structure size used (depth 7, branching factor 5), the linked list method was efficient in managing memory while yielding nodes for processing.
Conversely, the Pre-order traversal yielded nearly 56.86 executions per second, and Level-order using an array was the slowest at about 1.94 executions per second. This substantial difference highlights the inefficiency of array-based level-order traversal in terms of both memory and processing speed, especially at a significant tree width.
Tree Structure: The benchmark uses a random tree structure generated by makeRandomTree(depth, degree)
, which replicates varying depths and branching to test the algorithms under different conditions.
Alternatives: Other traversal methodologies include:
Overall, the benchmark’s evaluation of tree traversal methods provides essential insights into their performance characteristics, guiding developers in selecting the most suitable approach for their specific applications and constraints.