Back to Nvidia questions
CodingAutopilot C++

Nearest Node in a Binary Search Tree

Role: Autopilot C++

Frequency: Reported


You are given a pointer to a node in a low-level binary search tree containing integers and an integer query. Return a pointer to the node whose value is closest to the query.

Implement nearest_node in the retained starter code:

cpp
#include <iostream>
#include <cassert>
#include <new>

struct node {
    node * left;
    node * right;
    int value;
};

const node * nearest_node(const node * root, int query) {
    // TODO: Implement this function
    return nullptr;
}

node * add_integer(node * & n, int new_value) {
    if (!n) {
        n = new node{nullptr, nullptr, new_value};
        return n;
    } else if (n->value < new_value) {
        return add_integer(n->right, new_value);
    } else if (n->value > new_value) {
        return add_integer(n->left, new_value);
    } else {
        assert(false && "duplicate value added to tree");
    }
}

void cleanup(const node * n) {
    if (n) {
        cleanup(n->left);
        cleanup(n->right);
        delete n;
    }
}

class tree {
    node * root;

    public:
    tree() : root(nullptr) {}
    ~tree() { cleanup(root); }

    node * add(int new_value) {
        return ::add_integer(root, new_value);
    }

    const node * nearest_node(int query) const {
        return ::nearest_node(root, query);
    }
};

void test_case(const tree & t, int line, int query, const node * expected) {
    std::cout << "At line " << line << ": ";
    std::cout.flush();
    const node * result = t.nearest_node(query);
    if (result == expected) {
        std::cout << "OK" << std::endl;
    } else {
        std::cout << "Expected node { " << expected->value << " }, found node ";
        if (result) {
            std::cout << "{ " << result->value << " }" << std::endl;
        } else {
            std::cout << "nullptr" << std::endl;
        }
    }
}

int main() {
    {
        tree t;
        node* n10 = t.add(10);
        node* n20 = t.add(20);
        node* n30 = t.add(30);
        node* n40 = t.add(40);

        test_case(t, __LINE__, 0, n10);
        test_case(t, __LINE__, 10, n10);
        test_case(t, __LINE__, 14, n10);
        test_case(t, __LINE__, 16, n20);
        test_case(t, __LINE__, 20, n20);
        test_case(t, __LINE__, 24, n20);
        test_case(t, __LINE__, 26, n30);
        test_case(t, __LINE__, 30, n30);
        test_case(t, __LINE__, 34, n30);
        test_case(t, __LINE__, 36, n40);
        test_case(t, __LINE__, 40, n40);
        test_case(t, __LINE__, 100, n40);
    }
    {
        tree t;
        node* n20 = t.add(20);
        node* n10 = t.add(10);
        node* n40 = t.add(40);
        node* n30 = t.add(30);

        test_case(t, __LINE__, 0, n10);
        test_case(t, __LINE__, 10, n10);
        test_case(t, __LINE__, 14, n10);
        test_case(t, __LINE__, 16, n20);
        test_case(t, __LINE__, 20, n20);
        test_case(t, __LINE__, 24, n20);
        test_case(t, __LINE__, 26, n30);
        test_case(t, __LINE__, 30, n30);
        test_case(t, __LINE__, 34, n30);
        test_case(t, __LINE__, 36, n40);
        test_case(t, __LINE__, 40, n40);
        test_case(t, __LINE__, 100, n40);
    }
    {
        tree t;
        node* n20 = t.add(20);
        node* n30 = t.add(30);
        node* n10 = t.add(10);
        node* n40 = t.add(40);

        test_case(t, __LINE__, 0, n10);
        test_case(t, __LINE__, 10, n10);
        test_case(t, __LINE__, 14, n10);
        test_case(t, __LINE__, 16, n20);
        test_case(t, __LINE__, 20, n20);
        test_case(t, __LINE__, 24, n20);
        test_case(t, __LINE__, 26, n30);
        test_case(t, __LINE__, 30, n30);
        test_case(t, __LINE__, 34, n30);
        test_case(t, __LINE__, 36, n40);
        test_case(t, __LINE__, 40, n40);
        test_case(t, __LINE__, 100, n40);
    }
}

The source did not specify tie-breaking between equally close values or behavior for an empty tree.