Skip to content
Snippets Groups Projects
Commit 4d3398ab authored by Pavel Veselý's avatar Pavel Veselý
Browse files

tree successor

parent 15c53055
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.
// If the node is given, start searching a new position from that node.
Node* insert(int key, Node *node = nullptr) {
if (!root) {
root = new Node(key);
return root;
}
if (!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 node;
}
// 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) {
Node* node = tree.successor(nullptr);
for (const auto& element : 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));
}
void test_path(bool right) {
vector<int> numbers;
for (int i = 0; i < 10000000; i++)
numbers.push_back((int)(7.13*i));
Tree tree;
Node *node = nullptr;
if (right)
for (int key : numbers)
node = tree.insert(key, node);
else
for (int index = numbers.size() - 1; index >= 0; --index)
node = tree.insert(numbers[index], node);
test(numbers, tree);
}
void test_random() {
vector<int> sequence = {997};
for (int i = 2; i < 199999; i++)
sequence.push_back((sequence.back() * int64_t(997)) % 199999);
Tree tree;
for (const auto& element : sequence)
tree.insert(element);
sort(sequence.begin(), sequence.end());
test(sequence, tree);
}
vector<pair<string, function<void()>>> tests = {
{ "right_path", []{ test_path(true); } },
{ "left_path", []{ test_path(false); } },
{"random_tree", test_random },
};
#!/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, node=None):
"""Insert key into the tree.
If the key is already present, do nothing.
If the node is given, start searching a new position from that node.
"""
if self.root is None:
self.root = Node(key)
return self.root
if not node:
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
return node
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
from tree_successor import Tree
def test_tree(tree, sequence):
node = tree.successor(None)
for element in 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 test_random_tree():
sequence = [pow(997, i, 199999) for i in range(1, 199999)]
tree = Tree()
for i in sequence:
tree.insert(i)
sequence.sort()
test_tree(tree, sequence)
def test_path(right):
sequence = [int(7.13*i) for i in range(1000000)]
tree = Tree()
node = None
sequence_insert = sequence if right else reversed(sequence)
for key in sequence_insert:
node = tree.insert(key, node)
test_tree(tree, sequence)
tests = [
("random_tree", test_random_tree),
("right_path", lambda: test_path(True)),
("left_path", lambda: test_path(False)),
]
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))
# `tree_successor`
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.*`).
Source code templates can be found in [the git repository](https://gitlab.kam.mff.cuni.cz/datovky/assignments/-/tree/master).
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment