Парсинг дерева структур легко с getline ()? - PullRequest
0 голосов
/ 17 февраля 2020

Это разбавленная версия программы, над которой я работаю. В этом примере я хотел бы проанализировать текстовый файл и создать дерево структур Branch.

struct Branch {
    int value = -1;
    Branch *positive;
    Branch *negative;
}

Это пример того, как текстовый файл будет выглядеть ...

First Tree>
    Value:      5
    Positive:
        Value:      7
        Positive:   X
        Negative:
            Value:      23
            Positive:   X
            Negative:   X
    Negative:   X
Another Tree>
    Value:      1
    Positive:
        Value:      2
        Positive:   X
        Negative:   X
    Negative:
        Value:      3
        Positive:   X
        Negative:   X
Third Tree>
    Value:      19
    Positive:   X
    Negative:   X

Имена, предшествующие >, следует игнорировать. всегда будут 3 дерева в правильном порядке, и у меня есть указатели на них.

Branch *firsttree;
Branch *anothertree;
Branch *thirdtree;

Я бы вообразил создание массива указателей на 3 указателя ветвей (firsttree, чужое дерево, третье дерево), тогда итерация по ним будет самым простым способом убедиться, что мы можем поместить это в al oop.

Я бы хотел использовать getline() для этого и не полагаться на какую-то библиотеку синтаксического анализа .

Это некоторый псевдокод того, что, как я ожидаю, будет выглядеть после прочтения данных:

//firsttree
{
    value: 5,
    positive: {
        value: 7,
        positive: nullptr,
        negative: {
            value: 23,
            positive: nullptr,
            negative: nullptr
        }
    },
    negative: nullptr
}

//anothertree
{
    value: 1,
    positive: {
        value: 2,
        positive: nullptr,
        negative: nulptr
    },
    negative: {
        value: 3,
        positive: nullptr,
        negative: nulptr
    }
}

//thirdtree
{
    value: 19,
    positive: nullptr,
    negative: nulptr
}

Вот оно в формате изображения: enter image description here

Есть ли способ легко l oop через входной файл, опираясь на std::getline()? Если да, не могли бы вы дать мне некоторый psuedocode для его достижения, поскольку я в основном заблудился, отслеживая индекс и переходя на дочерние узлы. Большое вам спасибо!

1 Ответ

0 голосов
/ 19 февраля 2020

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

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

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

Например, когда нужно выполнить синтаксический анализ ветви:

  • сначала прочитайте значение
  • затем рекурсивно считывает другую ветвь для положительной стороны (используя тот же код синтаксического анализа, чтобы он мог обрабатывать чтение еще большего количества ветвей)
  • затем рекурсивно считывает другую ветвь для отрицательной стороны (используя тот же код синтаксического анализа так что он может обрабатывать чтение еще больше веток)

Таким образом, и считывающая, и печатная части являются рекурсивными:

Вы можете попробовать это здесь: https://onlinegdb.com/BkWv_G9mI

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>

struct Branch {
    int value;
    Branch *positive;
    Branch *negative;
};

Branch *firsttree   = NULL;
Branch *anothertree = NULL;
Branch *thirdtree   = NULL;

void printbranch(Branch *branch, std::string indent)
{
    std::cout << "{\n";
    std::cout << indent << "    value: " << branch->value << ",\n";

    std::cout << indent << "    positive: ";
    if (branch->positive)
        printbranch(branch->positive, indent + "    ");
    else
        std::cout << "nullptr,\n";

    std::cout << indent << "    negative: ";
    if (branch->negative)
        printbranch(branch->negative, indent + "    ");
    else
        std::cout << "nullptr\n";

    std::cout << indent << "}\n";
}

void printtree(std::string treename, Branch *branch)
{
    std::cout << "//" << treename << "\n";
    printbranch(branch, "");
    std::cout << std::endl; // now we want to flush the output
}

Branch* readbranch(std::ifstream &file)
{
    Branch *branch = new Branch;
    std::string line, token, value;
    for (int currentitem = 0; currentitem < 3; currentitem++)
    {
        std::getline(file, line);
        std::istringstream ss(line);
        ss >> token;

        if (token == "Value:")
            ss >> branch->value;
        else if (token == "Positive:")
            branch->positive = !(ss >> value)?readbranch(file):nullptr;
        else if (token == "Negative:")
            branch->negative = !(ss >> value)?readbranch(file):nullptr;
    }
    return branch;
}

int main()
{
    std::string line;
    std::ifstream file("input.txt");

    // read the firsttree
    std::getline(file, line); // read the line with the >
    firsttree = readbranch(file);

    // read anothertree
    std::getline(file, line); // read the line with the >
    anothertree = readbranch(file);

    // read the thirdtree
    std::getline(file, line); // read the line with the >
    thirdtree = readbranch(file);

    // print the trees
    printtree("firsttree",firsttree);
    printtree("anothertree",anothertree);
    printtree("thirdtree",thirdtree);

    return 0;
}
...