Нужна помощь в создании дерева случайных выражений с ограниченной глубиной в C ++ - PullRequest
0 голосов
/ 22 декабря 2019

Я нашел этот пример: Вставка узлов в деревья выражений и внесла несколько небольших изменений:

class Node {
public:
    std::string data;
    Node* left, * right;
    Node* parent; // operator
    Node(std::string d, Node* p) : data(d), left(NULL), right(NULL), parent(p) {}
};
class ExpressionTree {
public:
    Node* root;
    int tsize;
    ExpressionTree() : root(NULL), tsize(0) {}
    void insert(string s);
    bool isOperator(string value);
};
bool ExpressionTree::isOperator(string value) {
    if (value == "+" || value == "-" ||
        value == "*" || value == "/" ||
        value == "==")
        return true;
    return false;
}
void ExpressionTree::insert(std::string s) {
    if (root == NULL) {
        root = new Node(s, NULL);
        ++tsize;
    }
    else {
        Node* current = root;
        while (true) {
            if (isOperator(current->data)) {
                if (current->left == NULL) {
                    current->left = new Node(s, current);
                    ++tsize;
                    return;
                }
                else if (current->right == NULL) {
                    current->right = new Node(s, current);
                    //++tsize;
                    return;
                }
                else {
                    if (isOperator(current->left->data)) {
                        current = current->left;
                        continue;
                    }
                    else if (isOperator(current->right->data)) {
                        current = current->right;
                        continue;
                    }
                    else {
                        if (current->parent) {
                            current = current->parent->right;
                            continue;
                        }
                        else {
                            //std::cout << "Error: only nodes who hold operators "
                            //  << "can have children." << std::endl;
                            return;
                        }
                    }
                }
            }
            else {
                //std::cout << "Error: only nodes who hold operators "
                //  << "can have children." << std::endl;
                return;
            }
        }
    }
}
void inorder(Node* node) {
    if (node) {
        if (node->left && node->parent)
            cout << "(";
        inorder(node->left);
        cout << node->data;
        inorder(node->right);
        if (node->right && node->parent)
            cout << ")";
    }
}

Мне нужно создать дерево случайных выражений с ограниченной глубиной на основевходные векторы

int maxDepth = 2;
vector<string> operands = { "A", "B", "C" };
vector<string> operators = { "+", "*", "-" };

Было бы замечательно, если бы что-то подобное могло быть реализовано:

ExpressionTree expression = generateRandomTree(operands, operators, maxDepth);

Возможные решения порядка в этом случае: A, B, C(глубина дерева = 1) или A + B, A - A, C - A и т. д., если глубина дерева> 1.

Как и в предыдущей ссылке, для создания допустимого выражения должны применяться следующие правила:

  • Каждый узел имеет ноль, одного или двух дочерних элементов.
  • Только узлы, содержащие операторы, могут иметь дочерние элементы.
  • Все конечные узлы должны быть операндами.

Метод insert хорошо работает, но я просто нене знаю, как сгенерировать дерево случайных выражений на основе этого кода. Я ценю вашу помощь в решении этой проблемы.

Редактировать: Подумайте вслух, вероятно, мне следует просто повторить выполнение insert со случайным операндом или случайным оператором (вероятность 50-50%), пока все листовые узлы не станут операндами или не будет достигнута максимальная глубина. Кроме того, для уровня дерева maxDepth (если он достигнут) мне понадобятся только случайные операнды. Тем не менее, реализация - это проблема, с которой я столкнулся ..

1 Ответ

2 голосов
/ 22 декабря 2019

Я думаю, что сделал это ... По крайней мере, результаты кажутся хорошими.

#include <iostream> 
#include <string> 
#include <vector> 
#include <ctime>
using namespace std;

class Node {
public:
    string data;
    string type;
    Node* left, * right;
    Node* parent; // operator
    Node(string d, string t) : data(d), type(t), left(NULL), right(NULL), parent(NULL) {}
};
class ExpressionTree {
public:
    Node* root;
    int tsize;
    ExpressionTree() : root(NULL), tsize(0) {}
    //void insert(string s);
    void addLeafNode(Node* node);
    bool isOperator(string value);
};
bool ExpressionTree::isOperator(string value) {
    if (value == "+" || value == "-" ||
        value == "*" || value == "/" ||
        value == "==")
        return true;
    return false;
}
void inorder(Node* node) {
    if (node) {
        if (node->left && node->parent)
            cout << "(";
        inorder(node->left);
        cout << node->data;
        inorder(node->right);
        if (node->right && node->parent)
            cout << ")";
    }
}
void randomOperandOrOperator(vector<string> operands, vector<string> operators, string* value, string* type, bool maxDepth) {
    if (!operators.size())
        maxDepth = 1;
    if (maxDepth == 1) {
        *value = operands[rand() % operands.size()];
        *type = "operand";
    }
    else {
        int percentage = rand() % 100 + 1;
        if (percentage <= 50) {
            *value = operands[rand() % operands.size()];
            *type = "operand";
        }
        else {
            *value = operators[rand() % operators.size()];
            *type = "operator";
        }
    }
}
Node* getFirstFreeOperatorLeafNode(Node* root) {
    Node* res = NULL;
    if (root == NULL)
        return NULL;
    if (root->type == "operator") {
        if (root->left == NULL || root->right == NULL)
            return root;
        if(root->left != NULL)
            res = getFirstFreeOperatorLeafNode(root->left);
        if (res == NULL && root->right != NULL)
            res = getFirstFreeOperatorLeafNode(root->right);
    }
    return res;
}
void ExpressionTree::addLeafNode(Node* node) {
    // tree is empty?
    if (root == NULL) {
        root = node;
        node->parent = NULL;
        node->left = NULL;
        node->right = NULL;
    }
    else {
        // add new node to first free operator leaf node
        Node* lastOperatorLeaf = getFirstFreeOperatorLeafNode(root);
        if (lastOperatorLeaf != NULL) {
            if (lastOperatorLeaf->left == NULL) {
                lastOperatorLeaf->left = node;
                node->parent = lastOperatorLeaf->left;
            }
            else
                if (lastOperatorLeaf->right == NULL) {
                    lastOperatorLeaf->right = node;
                    node->parent = lastOperatorLeaf->right;
                }
        }
    }
}
int getDepth(Node* node){
    if (node == NULL)
        return 0;
    else{
        int lDepth = getDepth(node->left);
        int rDepth = getDepth(node->right);

        if (lDepth > rDepth)
            return(lDepth + 1);
        else return(rDepth + 1);
    }
}

int main() {
    srand(time(NULL));
    vector<string> operands = { "A", "B", "C" };
    vector<string> operators = { "+", "*", "-" };

    int maxDepth = 5;
    for (int i = 0; i < 5; i++) {
        ExpressionTree expression;
        do {
            string value, type;
            randomOperandOrOperator(operands, operators, &value, &type, (getDepth(expression.root) + 1 >= maxDepth));
            expression.addLeafNode(new Node(value, type));
        } while (getFirstFreeOperatorLeafNode(expression.root) != NULL);
        cout << i + 1 << ". depth: " << getDepth(expression.root) << " => ";
        inorder(expression.root);
        cout << endl;
    }
    return 0;
}

5 образцов для maxDepth = 5:

  1. глубина:2 => B * A
  2. глубина: 4 => ((B - A) * A) * (A * C)
  3. глубина: 5 => (((C - C)- A) + (B + B)) * C
  4. глубина: 1 => C
  5. глубина: 1 => A

Надеюсьэто может кому-то пригодиться, или, пожалуйста, дайте мне знать, если что-то нужно исправить.

...