Skip to content
Snippets Groups Projects
Commit 0f460c7f authored by Ondřej Mička's avatar Ondřej Mička
Browse files

Tree successor

parent 4ce16bf0
No related branches found
No related tags found
No related merge requests found
test: tree_successor_test
./$<
CXXFLAGS=-std=c++11 -O2 -Wall -Wextra -g -Wno-sign-compare
tree_successor_test: tree_successor.h tree_successor_test.cpp test_main.cpp
$(CXX) $(CXXFLAGS) $^ -o $@
clean:
rm -f tree_successor_test
.PHONY: clean test
#include <cstdlib>
#include <functional>
#include <iostream>
#include <string>
#include <utility>
#include <vector>
using namespace std;
extern vector<pair<string, function<void()>>> tests;
void expect_failed(const string& message) {
cerr << "Test error: " << message << endl;
exit(1);
}
int main(int argc, char* argv[]) {
vector<string> required_tests;
if (argc > 1) {
required_tests.assign(argv + 1, argv + argc);
} else {
for (const auto& test : tests)
required_tests.push_back(test.first);
}
for (const auto& required_test : required_tests) {
bool found = false;
for (const auto& test : tests)
if (required_test == test.first) {
cerr << "Running test " << required_test << endl;
test.second();
found = true;
break;
}
if (!found) {
cerr << "Unknown test " << required_test << endl;
return 1;
}
}
return 0;
}
// A node of the tree
class Node {
public:
int key;
Node* left;
Node* right;
Node* parent;
// Constructor
Node(int key, Node* parent=nullptr) {
this->key = key;
this->parent = parent;
this->left = nullptr;
this->right = nullptr;
}
};
// Binary tree
class Tree {
public:
// Pointer to root of the tree; nullptr if the tree is empty.
Node* root = nullptr;
// Insert a key into the tree.
// If the key is already present, nothing happens.
void insert(int key) {
if (!root) {
root = new Node(key);
return;
}
Node* node = root;
while (node->key != key) {
if (key < node->key) {
if (!node->left)
node->left = new Node(key, node);
node = node->left;
} else {
if (!node->right)
node->right = new Node(key, node);
node = node->right;
}
}
}
// Return successor of the given node.
//
// The successor of a node is the node with the next higher key.
// Return nullptr if there is no such node.
// If the argument is nullptr, return the node with the smallest key.
Node* successor(Node* node) {
// TODO: Implement
}
// Destructor to free all allocated memory.
~Tree() {
Node* node = root;
while (node) {
Node* next;
if (node->left) {
next = node->left;
node->left = nullptr;
} else if (node->right) {
next = node->right;
node->right = nullptr;
} else {
next = node->parent;
delete node;
}
node = next;
}
}
};
#include <algorithm>
#include <functional>
#include <cstdint>
#include <string>
#include <utility>
#include <vector>
#include "tree_successor.h"
using namespace std;
// If the condition is not true, report an error and halt.
#define EXPECT(condition, message) do { if (!(condition)) expect_failed(message); } while (0)
void expect_failed(const string& message);
void test(const vector<int>& sequence) {
Tree tree;
for (const auto& element : sequence)
tree.insert(element);
vector<int> sorted_sequence(sequence);
sort(sorted_sequence.begin(), sorted_sequence.end());
Node* node = tree.successor(nullptr);
for (const auto& element : sorted_sequence) {
EXPECT(node, "Expected successor " + to_string(element) + ", got nullptr");
EXPECT(node->key == element,
"Expected successor " + to_string(element) + ", got " + to_string(node->key));
node = tree.successor(node);
}
EXPECT(!node, "Expected no successor, got " + to_string(node->key));
}
vector<pair<string, function<void()>>> tests = {
{"right_path", []
{ vector<int> numbers;
for (int i = 0; i < 10000; i++) numbers.push_back((int)(7.13*i));
test(numbers);
}
},
{"left_path", []
{ vector<int> numbers;
for (int i = 9999; i >= 0; i--) numbers.push_back((int)(7.13*i));
test(numbers);
}
},
{"random_tree", []
{ vector<int> numbers = {997};
for (int i = 2; i < 199999; i++)
numbers.push_back((numbers.back() * int64_t(997)) % 199999);
test(numbers);
}
},
};
#!/usr/bin/env python3
class Node:
"""Node in a binary tree `Tree`"""
def __init__(self, key, left=None, right=None, parent=None):
self.key = key
self.left = left
self.right = right
self.parent = parent
class Tree:
"""A simple binary search tree"""
def __init__(self, root=None):
self.root = root
def insert(self, key):
"""Insert key into the tree.
If the key is already present, do nothing.
"""
if self.root is None:
self.root = Node(key)
return
node = self.root
while node.key != key:
if key < node.key:
if node.left is None:
node.left = Node(key, parent=node)
node = node.left
else:
if node.right is None:
node.right = Node(key, parent=node)
node = node.right
def successor(self, node=None):
"""Return successor of the given node.
The successor of a node is the node with the next greater key.
Return None if there is no such node.
If the argument is None, return the node with the smallest key.
"""
# TODO: Implement
raise NotImplementedError
#!/usr/bin/env python3
import sys
import tree_successor
def test_sequence(sequence):
tree = tree_successor.Tree()
for i in sequence: tree.insert(i)
node = tree.successor(None)
for element in sorted(sequence):
assert node is not None, "Expected successor {}, got None".format(element)
assert node.key == element, "Expected successor {}, got {}".format(element, node.key)
node = tree.successor(node)
assert node is None, "Expected no successor, got {}".format(node.key)
def gen_increasing_seq():
return [int(7.13*i) for i in range(10000)]
tests = [
("right_path", lambda: test_sequence(gen_increasing_seq())),
("left_path", lambda: test_sequence(list(reversed(gen_increasing_seq())))),
("random_tree", lambda: test_sequence([pow(997, i, 199999) for i in range(1, 199999)])),
]
if __name__ == "__main__":
for required_test in sys.argv[1:] or [name for name, _ in tests]:
for name, test in tests:
if name == required_test:
print("Running test {}".format(name), file=sys.stderr)
test()
break
else:
raise ValueError("Unknown test {}".format(name))
Given an implementation of a simple binary search tree including parent
pointers, implement a `successor` method. The methods is given a node
and it should return another node of the tree with the next higher key
(i.e., the smallest of keys which are greater than the given one).
- If there is no such node, it should return a null pointer.
- The given node can also be a null pointer, in which case the method should
return the smallest node in the tree.
You can expect that `successor` method is never called on an empty tree.
You should submit the file `tree_successor.*` (but not the
`tree_successor_test.*`).
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment