logo

Árvore de expressão na estrutura de dados

A árvore de expressão é uma árvore usada para representar as várias expressões. A estrutura de dados em árvore é usada para representar as instruções expressionais. Nesta árvore, o nó interno sempre denota os operadores.

  • Os nós folha sempre denotam os operandos.
  • As operações são sempre realizadas nesses operandos.
  • O operador presente na profundidade da árvore tem sempre a prioridade mais alta.
  • O operador que não está muito na profundidade da árvore está sempre na prioridade mais baixa em comparação com os operadores que estão na profundidade.
  • O operando sempre estará presente na profundidade da árvore; por isso é considerado o Prioridade máxima entre todos os operadores.
  • Resumindo, podemos resumir como o valor presente na profundidade da árvore tem a prioridade mais alta em comparação com os outros operadores presentes no topo da árvore.
  • O principal uso dessas árvores de expressão é que elas são usadas para avaliar, analisar e modificar as diversas expressões.
  • Também é usado para descobrir a associatividade de cada operador na expressão.
  • Por exemplo, o operador + é associativo à esquerda e / é associativo à direita.
  • O dilema desta associatividade foi resolvido usando a expressão árvores.
  • Essas árvores de expressão são formadas usando uma gramática livre de contexto.
  • Associamos uma regra em gramáticas livres de contexto na frente de cada produção gramatical.
  • Essas regras também são conhecidas como regras semânticas e, usando essas regras semânticas, podemos construir facilmente as árvores de expressão.
  • É uma das partes principais do projeto do compilador e pertence à fase de análise semântica.
  • Nesta análise semântica, utilizaremos as traduções direcionadas à sintaxe e, na forma de saída, produziremos a árvore de análise anotada.
  • Uma árvore de análise anotada nada mais é do que a análise simples associada ao atributo type e a cada regra de produção.
  • O principal objetivo do uso das árvores de expressão é fazer expressões complexas e que possam ser facilmente avaliadas usando essas árvores de expressão.
  • É imutável e, uma vez criada uma árvore de expressão, não podemos alterá-la ou modificá-la ainda mais.
  • Para fazer mais modificações, é necessário construir totalmente a nova árvore de expressão.
  • Também é usado para resolver a avaliação de expressões postfixas, prefixas e infixas.

As árvores de expressão desempenham um papel muito importante na representação do nível de idioma código na forma de dados, que são armazenados principalmente na estrutura em forma de árvore. Também é usado na representação de memória do lambda expressão. Usando a estrutura de dados em árvore, podemos expressar a expressão lambda de forma mais transparente e explícita. Ele é criado primeiro para converter o segmento de código em segmento de dados para que a expressão possa ser facilmente avaliada.

A árvore de expressão é uma árvore binária em que cada nó externo ou folha corresponde ao operando e cada nó interno ou pai corresponde aos operadores, então, por exemplo, árvore de expressão para 7 + ((1+8)*3) seria:

Árvore de expressão na estrutura de dados

Seja S a árvore de expressão

Se S não for nulo, então

Se S.value for um operando, então

Retornar S.valor

x = resolver (S.esquerda)

y = resolver (S.direito)

Retornar calcular (x, y, S.valor)

Aqui no exemplo acima, a árvore de expressões usou gramática livre de contexto.

Temos algumas produções associadas a algumas regras de produção nesta gramática, conhecidas principalmente como regras semânticas . Podemos definir a produção de resultados a partir das regras de produção correspondentes usando essas regras semânticas. Aqui usamos o parâmetro value, que calculará o resultado e o retornará ao símbolo inicial da gramática. S.left calculará o filho esquerdo do nó e, da mesma forma, o filho direito do nó pode ser calculado usando o parâmetro S.right.

Uso da árvore de expressão

  1. O principal objetivo do uso das árvores de expressão é fazer expressões complexas e que possam ser facilmente avaliadas usando essas árvores de expressão.
  2. Também é usado para descobrir a associatividade de cada operador na expressão.
  3. Também é usado para resolver a avaliação de expressões postfixas, prefixas e infixas.

Implementação de uma árvore de expressão

Para implementar a árvore de expressão e escrever seu programa, seremos obrigados a usar uma estrutura de dados de pilha.

Como sabemos que a pilha é baseada no princípio LIFO do último a entrar, primeiro a sair, o elemento de dados inserido recentemente na pilha foi retirado sempre que necessário. Para sua implementação são utilizadas as duas principais operações da pilha, push e pop. Usando a operação push, colocaremos o elemento de dados na pilha e, usando a operação pop, removeremos o elemento de dados da pilha.

Principais funções da pilha na implementação da árvore de expressão:

Em primeiro lugar, faremos a varredura da expressão dada da esquerda para a direita e, em seguida, verificaremos um por um o caractere identificado,

  1. Se um caractere digitalizado for um operando, aplicaremos a operação push e o colocaremos na pilha.
  2. Se um personagem digitalizado for um operador, aplicaremos a operação pop nele para remover os dois valores da pilha para torná-los seus filhos e, depois disso, colocaremos de volta o nó pai atual na pilha.

Implementação de árvore de expressão em linguagem de programação C

 // C program for expression tree implementation #include #include /* The below structure node is defined as a node of a binary tree consists of left child and the right child, along with the pointer next which points to the next node */ struct node { char info ; struct node* l ; struct node* r ; struct node* nxt ; }; struct node *head=NULL; /* Helper function that allocates a new node with the given data and NULL left and right pointers. */ struct node* newnode(char data) { struct node* node = (struct node*) malloc ( sizeof ( struct node ) ) ; node-&gt;info = data ; node-&gt;l = NULL ; node-&gt;r = NULL ; node-&gt;nxt = NULL ; return ( node ) ; } void Inorder(struct node* node) { if ( node == NULL) return ; else { /* first recur on left child */ Inorder ( node-&gt;l ) ; /* then print the data of node */ printf ( &apos;%c &apos; , node-&gt;info ) ; /* now recur on right child */ Inorder ( node-&gt;r ) ; } } void push ( struct node* x ) { if ( head == NULL ) head = x ; else { ( x )-&gt;nxt = head ; head = x ; } // struct node* temp ; // while ( temp != NULL ) // { // printf ( &apos; %c &apos; , temp-&gt;info ) ; // temp = temp-&gt;nxt ; // } } struct node* pop() { // Poping out the top most [pointed with head] element struct node* n = head ; head = head-&gt;nxt ; return n ; } int main() { char t[] = { &apos;X&apos; , &apos;Y&apos; , &apos;Z&apos; , &apos;*&apos; , &apos;+&apos; , &apos;W&apos; , &apos;/&apos; } ; int n = sizeof(t) / sizeof(t[0]) ; int i ; struct node *p , *q , *s ; for ( i = 0 ; i <n ; i++ ) { if read character is operator then popping two other elements from stack and making a binary tree ( t[i]="=" '+' || '-' '*' ' '^' s="newnode" t [ i ] p="pop()" q="pop()" s->l = q ; s-&gt;r = p; push(s); } else { s = newnode ( t [ i ] ) ; push ( s ) ; } } printf ( &apos; The Inorder Traversal of Expression Tree: &apos; ) ; Inorder ( s ) ; return 0 ; } </n>

A saída do programa acima é:

 X + Y * Z / W 

Implementação de árvore de expressões em linguagem de programação C++

 // C++ program for expression tree #include using namespace std ; /* The below class node is defined as a node of a binary tree consists of left child and the right child, along with the pointer next which points to the next node */ class node { public: char info ; node* l ; node* r ; node* nxt = NULL ; node ( char c ) { this-&gt;info = c ; l = NULL ; r = NULL ; } node() { l = NULL ; r = NULL ; } friend class Stack ; friend class tree ; } ; class Stack { node* head = NULL ; public: void push ( node* ) ; node* pop() ; friend class tree ; } ; class tree { public: void inorder ( node* x ) { // cout&lt;<'tree in inorder traversal is: '<l ) ; cout <info <r } void stack::push( node* x { if ( head="=" null we are inserting here nodes at the top of stack [following lifo principle] else x->nxt = head ; head = x ; } } node* Stack::pop() { // Poping out the top most [ pointed with head ] element node* p = head ; head = head-&gt;nxt ; return p ; } int main() { string str = &apos;XYZ*+W/&apos; ; // If you wish take input from user: //cout &lt;&lt; &apos;Insert Postorder Expression: &apos; &lt;&gt; s; Stack s ; tree t ; node *p, *q, *re; int n = str.length() ; for ( int i = 0 ; i <n ; i++ ) { if ( str[ i ]="=" '+' || '-' '*' ' '^') re="new" node( str[i] p="s.pop()" q="s.pop()" re->l = q ; re-&gt;r = p ; s.push(re) ; } else { re = new node( str[ i ] ) ; s.push(re) ; } } cout &lt;&lt; &apos; The Inorder Traversal of Expression Tree: &apos; ; t.inorder(re) ; return 0 ; } </n></'tree>

A saída do programa acima é:

 X + Y * Z / W 

Implementação da árvore de expressões na linguagem de programação Java

 // Java program for expression tree import java.util.* ; /* The below class node is defined as a node of a binary tree consists of left child and the right child, along with the pointer next which points to the next node */ class Node { char info ; Node l , r ; public Node(char data) { this.info = data ; l = null ; r = null ; } } public class Main { public static boolean isOperator ( char ch ) { if ( ch == &apos;+&apos; || ch == &apos;-&apos; || ch == &apos;*&apos; || ch == &apos;/&apos; || ch == &apos;^&apos; ) { return true ; } return false ; } public static Node Tree ( String postfix ) { Stack st = new Stack(); Node t1,t2,temp ; for ( int i = 0 ; i <p> <strong>The output of the above program is:</strong> </p> <pre> X + Y * Z / W </pre> <hr>