ist hier TC-Lösung auf jede Art von Traversierung eines N-ären Baum verallgemeinert, wo reorder<std::tuple, 2, 1, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O>
Das besondere ist, Fall des ursprünglichen Problems (binärer Baum in order traversal), da die 2 einen binären Baum anzeigt und die 1 eine Aktion nach Rekursion mit dem ersten Kind anzeigt. Die 2 und 1 können beliebige andere Werte annehmen.
#include <type_traits>
#include <utility>
#include <tuple>
// Concatenating std::index_sequences.
template <typename... Packs> struct concat;
template <typename Pack>
struct concat<Pack> {
using type = Pack;
};
template <std::size_t... Is, std::size_t... Js>
struct concat<std::index_sequence<Is...>, std::index_sequence<Js...>> {
using type = std::index_sequence<Is..., Js...>;
};
template <typename Pack1, typename Pack2, typename... Packs>
struct concat<Pack1, Pack2, Packs...> : concat<Pack1, typename concat<Pack2, Packs...>::type> {};
// In-order traversal for a complete binary tree whose level-order traversal is 0,1,2, ..., max-1.
template <std::size_t NumChildren, std::size_t ActionPoint, std::size_t Start, std::size_t Max, typename = void>
struct traversal {
using type = std::index_sequence<>; // So that concatenating changes nothing and ends the recursion.
};
// General recursion.
template <std::size_t Count, std::size_t NumChildren, std::size_t ActionPoint, std::size_t Start, std::size_t Max, typename Pack, bool ActionJustTookPlace = false>
struct concat_traversals_impl : concat_traversals_impl<Count + 1, NumChildren, ActionPoint, Start, Max,
typename concat<Pack, typename traversal<NumChildren, ActionPoint, NumChildren * Start + Count + 1, Max>::type>::type> {};
// 0
// / | \
// / | \
// 1 2 3
// /| \
// 4 5 6
// Above we see that the three children of node K is 3*K+1, 3*K+2, 3*K+3. In general, it is N*K+1, N*K+2, ..., N*K+N, where N is the number of children.
// If Count == ActionPoint (and ActionJustTookPlace == false), then concat the action, which is std::index_sequence<Start> in this case, but then let ActionJustTookPlace == true so that this does not happen infinitely (as Count still remains equal to ActionPoint) on the next template instantiation, and the primary template is used instead.
template <std::size_t NumChildren, std::size_t ActionPoint, std::size_t Start, std::size_t Max, typename Pack>
struct concat_traversals_impl<ActionPoint, NumChildren, ActionPoint, Start, Max, Pack, false> : concat_traversals_impl<ActionPoint, NumChildren, ActionPoint, Start, Max,
typename concat<Pack, std::index_sequence<Start>>::type, true> {};
// End the recursion when Count == NumChildren.
template <std::size_t NumChildren, std::size_t ActionPoint, std::size_t Start, std::size_t Max, typename Pack>
struct concat_traversals_impl<NumChildren, NumChildren, ActionPoint, Start, Max, Pack> {
using type = Pack;
};
// Special case of when Count == NumChildren and ActionPoint == NumChildren as well (this partial specialization is needed else there will be ambiguity compilng error).
template <std::size_t ActionPoint, std::size_t Start, std::size_t Max, typename Pack>
struct concat_traversals_impl<ActionPoint, ActionPoint, ActionPoint, Start, Max, Pack, false> : concat<Pack, std::index_sequence<Start>> {};
template <std::size_t NumChildren, std::size_t ActionPoint, std::size_t Start, std::size_t Max>
using concat_traversals = typename concat_traversals_impl<0, NumChildren, ActionPoint, Start, Max, std::index_sequence<>>::type;
template <std::size_t NumChildren, std::size_t ActionPoint, std::size_t Start, std::size_t Max> // Recursive call.
struct traversal<NumChildren, ActionPoint, Start, Max, std::enable_if_t<(Start < Max)>> {
using type = concat_traversals<NumChildren, ActionPoint, Start, Max>;
};
// Now the actual reordering.
template <typename Pack, typename Sequence> struct reorder_helper;
template <template <typename...> class P, typename... Ts, std::size_t... Is>
struct reorder_helper<P<Ts...>, std::index_sequence<Is...>> {
using type = P<std::tuple_element_t<Is, std::tuple<Ts...>>...>;
};
template <template <typename...> class P, std::size_t NumChildren, std::size_t ActionPoint, typename... Ts>
using reorder = typename reorder_helper<P<Ts...>, typename traversal<NumChildren, ActionPoint, 0, sizeof...(Ts)>::type>::type;
// Special syntax for reordering a pack.
template <std::size_t NumChildren, std::size_t ActionPoint, typename Pack> struct reorder_pack;
template <std::size_t NumChildren, std::size_t ActionPoint, template <typename...> class P, typename... Ts>
struct reorder_pack<NumChildren, ActionPoint, P<Ts...>> {
using type = reorder<P, NumChildren, ActionPoint, Ts...>;
};
// Testing
struct A{}; struct B{}; struct C{}; struct D{}; struct E{}; struct F{}; struct G{}; struct H{};
struct I{}; struct J{}; struct K{}; struct L{}; struct M{}; struct N{}; struct O{};
int main() {
static_assert (std::is_same<
reorder<std::tuple, 2, 1, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O>, // 2 means it is a binary tree, 1 means that we do left traversal, then the node action, then right traversal (i.e. inorder traversal).
std::tuple<H,D,I,B,J,E,K,A,L,F,M,C,N,G,O>
>::value, "");
static_assert (std::is_same<
reorder<std::tuple, 2, 0, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O>, // 2 means it is a binary tree, 0 means that we do the node action, then left traversal, and then right traversal (i.e. preorder traversal).
std::tuple<A,B,D,H,I,E,J,K,C,F,L,M,G,N,O>
>::value, "");
static_assert (std::is_same<
reorder<std::tuple, 2, 2, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O>, // 2 means it is a binary tree, 2 means that we do left traversal, then right traversal, then the node action (i.e. postorder traversal).
std::tuple<H,I,D,J,K,E,B,L,M,F,N,O,G,C,A>
>::value, "");
static_assert (std::is_same<
reorder_pack<3, 2, std::tuple<A,B,C,D,E,F,G,H,I,J,K,L,M,N,O>>::type, // 3 children per node. Do first child, second child, then node action, then do third child recursively.
std::tuple<N,O,E,F,B,G,H,I,C,J,A,K,L,D,M>
>::value, "");
}
Ersetzen Sie die Typen im Baum durch Indizes. Schau sie dir genau an. Sehen Sie eine Beziehung zwischen dem Wert eines Knotens und seinen Kindern? Denken Sie dann darüber nach, wie Sie diese Beziehung ausnutzen können, um eine In-Order-Traversierung des Baums durchzuführen. –