rec/fplus/tree.hpp

239 lines
6.0 KiB
C++
Raw Permalink Normal View History

2020-03-18 06:42:46 +00:00
// Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
// https://github.com/Dobiasd/FunctionalPlus
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <vector>
#include <queue>
namespace fplus
{
template <typename T>
struct tree
{
tree (const T& value, const std::vector<tree<T>>& children) :
value_(value), children_(children) {}
T value_;
std::vector<tree<T>> children_;
};
namespace internal
{
template <typename T>
tree<T> make_singleton_tree(const T& x)
{
return {x, {}};
}
} // namespace internal
namespace internal
{
template <typename BinaryPredicate, typename T>
std::vector<tree<T>> presort_trees(BinaryPredicate tree_is_child_of,
std::vector<tree<T>> xs_orig)
{
auto xs = fplus::convert_container<std::list<tree<T>>>(xs_orig);
std::vector<tree<T>> result;
while (!xs.empty())
{
for (auto it = std::begin(xs); it != std::end(xs);)
{
bool has_children = false;
for (auto it_rest = std::begin(xs); it_rest != std::end(xs); ++it_rest)
{
if (it_rest != it && tree_is_child_of(*it_rest, *it))
{
has_children = true;
}
}
if (!has_children)
{
result.push_back(*it);
it = xs.erase(it);
}
else
{
++it;
}
}
}
return result;
}
template <typename BinaryPredicate, typename TreeCont> // todo: name?
TreeCont trees_from_sequence_helper(
BinaryPredicate tree_is_child_of, TreeCont xs_unsorted)
{
TreeCont result;
auto xs = presort_trees(tree_is_child_of, xs_unsorted);
for (auto it = std::begin(xs); it != std::end(xs); ++it)
{
const auto find_pred = bind_1st_of_2(tree_is_child_of, *it);
auto it_find_begin = it;
internal::advance_iterator(it_find_begin, 1);
auto parent_it = std::find_if(it_find_begin, std::end(xs), find_pred);
if (parent_it != std::end(xs))
{
parent_it->children_.push_back(*it);
}
else
{
result.push_back(*it);
}
}
return result;
}
} // namespace internal
// API search type: trees_from_sequence : (((a, a) -> Bool), [a]) -> [Tree a]
// fwd bind count: 1
// Converts the sequence into a tree considering the given binary predicate.
template <typename BinaryPredicate, typename Container> // todo: name?
std::vector<tree<typename Container::value_type>> trees_from_sequence(
BinaryPredicate is_child_of, const Container& xs)
{
internal::check_binary_predicate_for_container<BinaryPredicate, Container>();
typedef typename Container::value_type T;
typedef tree<T> Tree;
const auto singletons = transform_convert<std::vector<Tree>>(
internal::make_singleton_tree<T>, xs);
const auto tree_is_child_of =
[is_child_of](const tree<T>& a, const tree<T>& b) -> bool
{
return is_child_of(a.value_, b.value_);
};
return internal::trees_from_sequence_helper(
tree_is_child_of, std::move(singletons));
}
namespace internal
{
// -1 = a < b
// 0 = a == b
// 1 = b < a
template <typename T>
int tree_cmp(const tree<T>& a, const tree<T>& b)
{
if(a.value_ < b.value_)
{
return -1;
}
else if(b.value_ < a.value_)
{
return 1;
}
else
{
const auto results = zip_with(tree_cmp<T>,
sort_by(tree_cmp<T>, a.children_),
sort_by(tree_cmp<T>, b.children_));
return just_with_default(0, find_first_by(
bind_1st_of_2(is_not_equal<int>, 0),
results));
}
}
template <typename T>
bool tree_less(const tree<T>& a, const tree<T>& b)
{
return tree_cmp(a, b) < 0;
}
} // namespace internal
namespace internal
{
template <typename T>
bool are_normalized_trees_equal(const tree<T>& a, const tree<T>& b)
{
if (a.value_ != b.value_ || a.children_.size() != b.children_.size())
{
return false;
}
else
{
return all(zip_with(are_normalized_trees_equal<T>,
a.children_, b.children_));
}
}
template <typename T>
tree<T> normalize_tree(tree<T> x)
{
x.children_ = sort_by(
internal::tree_less<T>,
transform(normalize_tree<T>, x.children_));
return x;
}
} // namespace internal
// API search type: are_trees_equal : (Tree a, Tree a) -> Bool
// fwd bind count: 1
template <typename T>
bool are_trees_equal(const tree<T>& a, const tree<T>& b)
{
return internal::are_normalized_trees_equal(
internal::normalize_tree(a), internal::normalize_tree(b));
}
// API search type: tree_size : Tree a -> Int
// fwd bind count: 0
// A tree with only one element (root) has size 1.
template <typename T>
std::size_t tree_size(const tree<T>& x)
{
return 1 + sum(transform(tree_size<T>, x.children_));
}
// API search type: tree_depth : Tree a -> Int
// fwd bind count: 0
// A tree with only one element (root) has depth 1.
template <typename T>
std::size_t tree_depth(const tree<T>& x)
{
return 1 + just_with_default<std::size_t>(0,
maximum_maybe(transform(tree_depth<T>, x.children_)));
}
// API search type: flatten_tree_depth_first : Tree a -> [a]
// fwd bind count: 0
template <typename T>
std::vector<T> flatten_tree_depth_first(const tree<T>& x)
{
return prepend_elem(x.value_,
transform_and_concat(flatten_tree_depth_first<T>, x.children_));
}
// API search type: flatten_tree_breadth_first : Tree a -> [a]
// fwd bind count: 0
template <typename T>
std::vector<T> flatten_tree_breadth_first(const tree<T>& x)
{
std::vector<T> result;
result.reserve(tree_size(x));
std::queue<const tree<T>*> q;
q.push(&x);
while (!q.empty())
{
const auto current = q.front();
q.pop();
result.push_back(current->value_);
for (const auto& c : current->children_)
{
q.push(&c);
}
}
return result;
}
} // namespace fplus