Как я могу сохранить общее дерево в файле?

0

Я имею общую реализацию дерева, написанную в 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>

но как я могу сохранить тип класса?

  • 0
    Вы должны использовать некоторую библиотеку сериализации, такую как Apache Thrift или Google Protobuf. Но дерево как тип данных может не поддерживаться, и поэтому вам нужно обойти это. НО заставить их работать для шаблонного класса будет настоящей проблемой :(
  • 0
    Большое спасибо! ...
Показать ещё 5 комментариев
Теги:
tree
store
generic-programming

2 ответа

0
Лучший ответ

Для каждого значения в дереве вам необходимо связать тип. Таким образом, каждый элемент дерева является парой типа значения и значения и списка дочерних элементов. В вашем файле вы должны хранить эту информацию для каждого узла.

Вы можете считать, что 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;
  • 0
    Ваша идея великолепна, но не могли бы вы объяснить, почему использование unique_ptr и boost list должно быть лучше? Ваш ответ работает с XML вместо JSON?
  • 0
    Когда я читал ваш код, я думал, что T должен быть базовым типом для всех ваших значений в вашем дереве, иначе ваше дерево будет только деревом T, что означает, что дерево не сможет иметь детей дерево B. Здесь вам нужен полиморфный тип, если у вас есть полиморфный тип, вы должны использовать указатель, если у вас есть указатель, уникальный указатель отлично подходит для применения RAII. Boost :: container :: list здесь, чтобы избежать необработанного указателя на список. Конечно, вы можете использовать XML вместо JSON, это просто формат сериализации
Показать ещё 1 комментарий
0

Я думаю, вы используете указатели для связи между узлами. что-то вроде:

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> карте, используемой для перевода указателя на индекс в векторе.

теперь напишите узлы в файл с индексами вместо указателей.

когда вы читаете из файла, вам нужно сделать это наоборот и перевести указатели в указатели.

  • 0
    используя ваше решение, как вы конвертируете из указателей в int? Вам тоже нужно хранить карту? Также обратите внимание, что мне не нужно хранить указатели, я могу перестроить дерево при загрузке файла
  • 0
    Нет, деревья обычно не хранятся таким образом. Это было бы пустой тратой усилий программиста. Вместо этого деревья обычно хранятся рекурсивно, например, как (root,[child1,child2,...childN]) , где root - это значение корневого узла, а left и right - его дочерние элементы. Пустое дерево есть () . Это только пример, и фактический формат может быть почти любым, при условии, что вы можете отличить разделители (в данном случае скобки, скобки и запятые) от значений узлов.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню