Я имею общую реализацию дерева, написанную в C++, которая может хранить любой тип (int, float, string и т.д.).
template<class T> class Tree {
public:
// Class interface
private:
T node;
std::list<Tree<T>*>* children;
};
и у меня есть программа (написанная в C++), которая принимает в качестве входных данных исходное дерево и дает в выводе другое дерево на основе набора правил (хранящихся в файле).
Any instance of class A become an instance of class X
Any instance of class B become an instance of class Y
Any instance of class C become an instance of class Z
Например, предположим, что у меня есть это дерево ввода A (B (C)) (узел A имеет B как дочерний элемент, а B имеет C как дочерний). На основе файла правила моя программа дает мне это дерево X (Y (Z)). Мой вопрос: как я могу сохранить в файле набор правил? Как сохранить тип дерева в этом файле? Я думаю использовать XML для хранения правил, как это
<translationUnit>
<from>
<A>
<B>
<C></C>
</B>
</A>
</from>
<to>
<X>
<Y>
<Z></Z>
</Y>
</X>
<to>
</translationUnit>
но как я могу сохранить тип класса?
Для каждого значения в дереве вам необходимо связать тип. Таким образом, каждый элемент дерева является парой типа значения и значения и списка дочерних элементов. В вашем файле вы должны хранить эту информацию для каждого узла.
Вы можете считать, что json хранит сериализованную версию вашего дерева, ее легко читать и существует много хорошей библиотеки c++. Например, дерево ввода будет:
{
type: "A",
value: "value of the first node,
children: [
{
type: "B"
value: "a value ...",
children: [
{
type: "C",
value: "a value ...",
}
]
}
]
}
ваш результат станет следующим:
{
type: "X",
value: "value of the first node,
children: [
{
type: "Y"
value: "a value ...",
children: [
{
type: "Z",
value: "a value ...",
}
]
}
]
}
и в вашем файле конфигурации вы можете сохранить каждое преобразование типа:
[
{ from: "A", to: "X" },
{ from: "B", to: "Y" },
{ from: "C", to: "Z" }
]
Если вы хотите сохранить детей типа B внутри дерева типа A, с вашим интерфейсом, A и B должны использовать базовый тип, и вы должны использовать указатели для хранения вашего члена узла. Если вы не хотите управлять им вручную, используйте unique_ptr:
unique_ptr<T> node;
После этого у вас есть указатель на список указателей на деревья, это большой указатель на управление, если вы хотите избежать указателя на список, вы можете использовать boost :: container :: list, которые разрешают контейнеры неполного типа, После этого вам не нужно указывать указатель на дерево, хранящееся в списке, значение Дерево будет выполнять задание.
boost::container::list<Tree<T> > children;
Я думаю, вы используете указатели для связи между узлами. что-то вроде:
class node{
int value;
node* first_child;
node* next_sibling;
};
вы можете создать узел сериализации с индексами вместо указателей. что-то вроде:
class node2{
int value;
int id_first_child;
int id_next_sibling;
};
Теперь вы можете сложить дерево. означает превратить его в массив.
добавьте все указатели узлов к vector<node*>
и к map<node*,int>
карте, используемой для перевода указателя на индекс в векторе.
теперь напишите узлы в файл с индексами вместо указателей.
когда вы читаете из файла, вам нужно сделать это наоборот и перевести указатели в указатели.
(root,[child1,child2,...childN])
, где root
- это значение корневого узла, а left
и right
- его дочерние элементы. Пустое дерево есть ()
. Это только пример, и фактический формат может быть почти любым, при условии, что вы можете отличить разделители (в данном случае скобки, скобки и запятые) от значений узлов.