有没有办法在 O(k) 中创建一个有 k 个节点的空 avl_tree?

is there a way to create an empty avl_tree with k nodes in O(k)?

我想创建一棵 AVL 树,节点的键是 O(k) 时间内从 0 到 k 的数字。 我知道可以在 O(k) 中创建具有相同条件的常规搜索树,但我不知道如何使用 AVL 树来做到这一点。

谢谢!

一个想法可能是首先确定给定参数的树的形状。我们可以选择所谓的 complete tree,有时也称为“接近完成”。这唯一地定义了给定数量的节点的形状。

我们可以计算出那棵树的高度是多少,以及那棵树最底层最右边的叶子中存储的值是多少。稍加改动,就可以很容易地推导出这两个值的公式。

利用这些信息,您可以递归地构建树,在构建树时使用中序遍历,其中每个下一个节点将具有下一个顺序值。

在 AVL 树中,您需要存储平衡因子(-1、0 或 1)。在这棵树中,大多数节点的平衡为 0,除了从根到底层最右边叶子的路径上的一些节点:其中一些节点是左重的,平衡因子为 -1。这些可以在构建树后通过从根执行二进制搜索来识别。

这是JavaScript中的交互式实现:

class Node {
    constructor(value) {
        this.value = value;
        this.left = null;
        this.right = null;
        this.balance = 0;
    }
    // Function to create a string representation of the subtree rooted at this node
    toString() {
        let text = "";
        if (this.right) {
            let lines = this.right.toString().split(/\n/);
            let mid = lines.findIndex(line => line[0] != " ");
            text = lines.map((line, i) => 
                i < mid ? "   " + line
                : i > mid ? " │ " + line
                : " ┌─" + line
            ).join("\n") + "\n";
        }
        text += "(" + this.value + ") " + (this.balance || "");
        if (this.left) {
            let lines = this.left.toString().split(/\n/);
            let mid = lines.findIndex(line => line[0] != " ");
            text += "\n" + lines.map((line, i) => 
                i < mid ? " │ " + line
                : i > mid ? "   " + line
                : " └─" + line
            ).join("\n");
        }
        return text;
    }
}

function createBalanced(k) {
    // Determine the height of the target tree
    let height = Math.floor(Math.log2(k + 1));
    // Determine the value that the right most node on the bottom level will have
    let lastBottom = (k + 1 - 2**height) * 2;    
    // The value which the next generated node will get
    let value = 0;
    
    // Recursive function for inorder generation of tree nodes
    function recur(depth) {
        if (depth > height) return null;
        let left = recur(depth + 1);
        // Check whether we are about to generate the last node at the bottom level
        if (value == lastBottom) height--; // This happens at the most once.
        let node = new Node(value);
        value++; // non-local variable!
        node.left = left;
        node.right = recur(depth + 1);
        return node;
    }
    
    let root = recur(0);
    // Identify the nodes that have a non-zero balance
    let node = root;
    while (node.value != lastBottom) {
        if (lastBottom < node.value) {
            node.balance = -1;
            node = node.left;
        } else {
            node = node.right;
        }
    }
    return root;
}

// I/O management in this snippet

function refresh() {
    let k = +input.value;
    if (k >= 0 && k <= 126) {
        let tree = createBalanced(k);
        output.textContent = tree.toString();
    } else {
        output.textContent = "Please enter a value between 0 and 126";
    }
}

let input = document.querySelector("input");
let output = document.querySelector("pre");
input.addEventListener("input", refresh);
refresh();
k: <input type="number" size="4" value="12" min="0" max="126"><br>
Tree (turned 90°). The balance is printed after the node when it is non-zero:
<pre></pre>