Skip to content
Snippets Groups Projects
Commit 118c7b92 authored by David Mareček's avatar David Mareček
Browse files

assignment 1

parent a148e86d
Branches
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).
Files tree_successor_more_tests.{cpp,py} contain additional tests
for bugs discovered in students' solutions during this semester.
They are not included on recodex, but your program should pass them
in few seconds.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment