98 lines
3.0 KiB
C++
98 lines
3.0 KiB
C++
#include <iostream>
|
|
#include <string>
|
|
#include <optional>
|
|
#include <vector>
|
|
#include <variant>
|
|
#include <memory>
|
|
#include <tuple>
|
|
#include <stdexcept>
|
|
#include <sstream>
|
|
#include <cstdio>
|
|
|
|
using namespace std;
|
|
|
|
|
|
class NotationTree {
|
|
public:
|
|
using Data = variant<double, char>;
|
|
|
|
struct TreeNode {
|
|
Data data;
|
|
optional<size_t> left_idx, right_idx;
|
|
|
|
explicit TreeNode(const string& value) { data = parse_string(value); }
|
|
explicit TreeNode(const Data value) { data = value; }
|
|
|
|
[[nodiscard]] bool is_operator() const {
|
|
return std::holds_alternative<char>(data);
|
|
}
|
|
|
|
[[nodiscard]] char get_operator() const {
|
|
if (!is_operator()) { throw invalid_argument("Node is not operator"); }
|
|
return get<char>(data);
|
|
}
|
|
|
|
[[nodiscard]] double get_number() const {
|
|
if (is_operator()) { throw invalid_argument("Node is operator"); }
|
|
return get<double>(data);
|
|
}
|
|
};
|
|
|
|
static Data parse_string(const string& value) {
|
|
if (value == "+" || value == "-" || value == "*" || value == "/") {
|
|
return value[0];
|
|
}
|
|
return stod(value);
|
|
}
|
|
|
|
vector<TreeNode> nodes;
|
|
|
|
tuple<size_t, size_t> build_from_poland(const vector<Data>& datas, const size_t start_idx = 0) {
|
|
size_t this_idx = nodes.size();
|
|
nodes.emplace_back(datas[start_idx]);
|
|
if (!nodes.back().is_operator()) { return make_tuple(this_idx, start_idx + 1); }
|
|
auto [left_idx, right_start_idx] = build_from_poland(datas, start_idx + 1);
|
|
nodes[this_idx].left_idx = left_idx;
|
|
auto [right_idx, right_end_idx] = build_from_poland(datas, right_start_idx);
|
|
nodes[this_idx].right_idx = right_idx;
|
|
return make_tuple(this_idx, right_end_idx);
|
|
}
|
|
|
|
double calculate(const size_t idx = 0) {
|
|
if (!nodes[idx].is_operator()) {
|
|
return nodes[idx].get_number();
|
|
}
|
|
if (!nodes[idx].left_idx.has_value() || !nodes[idx].right_idx.has_value()) {
|
|
throw invalid_argument("Tree is not complete");
|
|
}
|
|
const double left_result = calculate(nodes[idx].left_idx.value()),
|
|
right_result = calculate(nodes[idx].right_idx.value());
|
|
switch (nodes[idx].get_operator()) {
|
|
case '+': return left_result + right_result;
|
|
case '-': return left_result - right_result;
|
|
case '*': return left_result * right_result;
|
|
case '/': return left_result / right_result;
|
|
default: throw invalid_argument("Invalid operator");
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
int main() {
|
|
ios::sync_with_stdio(false);
|
|
cin.tie(nullptr);
|
|
|
|
string poland_notation, token;
|
|
vector<NotationTree::Data> datas;
|
|
getline(cin, poland_notation);
|
|
stringstream ss(poland_notation);
|
|
while (ss >> token) {
|
|
datas.push_back(NotationTree::parse_string(token));
|
|
}
|
|
NotationTree tree;
|
|
tree.build_from_poland(datas);
|
|
printf("%f\n", tree.calculate());
|
|
|
|
return 0;
|
|
}
|