【问题标题】:Building an expression tree using a stack and a binary tree c使用堆栈和二叉树 c 构建表达式树
【发布时间】:2012-11-26 11:24:11
【问题描述】:

我得到一个算术公式,其中包含运算符 +、-、*、/ 和括号(这可能会或可能不会改变运算符的自然优先级)。示例如下:a / b + f – (c + d) * e – a * c。我被要求使用堆栈(实现为链表)来跟踪操作数和运算符:我的程序应该如何工作的示例如下:

  • 读取 a,压入操作数堆栈
  • 读取 /,推入操作符堆栈
  • 读取 b,压入操作数堆栈
  • 读取 +: 的优先级低于 / ,因此:
    • 从操作数堆栈中弹出 2 个操作数(a 和 b)
    • 从运算符堆栈弹出/
    • 创建子树并压入操作数堆栈
    • 操作符栈是空的,所以按 + 就可以了
  • 读取 f,压入操作数堆栈
  • 读取 - : 与 + 具有相同的优先级,因此:
    • 从操作数栈中弹出 2 个操作数
    • 从运算符堆栈中弹出运算符 +
    • 创建一棵树,以运算符 + 作为根,两个操作数作为左右子节点
    • 将创建的树的根推回操作数堆栈
    • 操作符堆栈是空的,所以推入它

我比较难理解的问题是如何区分操作数的优先级

这是我编写的代码的不完整版本:

#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>

typedef struct btnode Btree;
typedef struct node s_Node;

struct btnode {
    char info; 
    Btree *left; 
    Btree *right;
};


struct node {
    char element;
    s_Node*next;
}; 

typedef struct{
    s_Node *top_stack;
} stack_t; 

int IsOperator(char c);

main () {
    FILE* fp;
    stack_t operands;
    stack_t operators;
    char c;
    operands=NewStack();
    operators=NewStack();
    fp= fopen ("Myfile.txt", "r");
    if (fp== NULL)
        printf ("   FILE COULD NOT BE OPENED");
    else
    {
        c=getc(fp);
        while (!feof (fp))
        {
            if ( c== ' ');
            else 
            {
                printf ("Here is your character: %c\n", c);
                if (IsOperator (c))
                    Push (c, &operands);
                else if ( isalpha (c))


            }
        c=getc(fp);
        }
    }
}

int IsOperator(char c)
{   
    switch(c)
    {
        case '+':
        case '-':
        case '/':
        case '*':
        return 1;
        default:
        return 0;
    }
} 

stack_t NewStack()
{
    stack_t *n_stack;
    n_stack=(stack_t*)malloc(sizeof(stack_t));
    n_stack->top_stack=NULL;
    return (*n_stack);  
}

int Push(char e, stack_t *q)
{       
    s_Node *nn;
    nn= (s_Node*)malloc(sizeof(s_Node));

    if(Full(*q))
    {
        printf("\n\t Stack is Full !! \n\n");
        return 0;   // return 0 if enstack NOT successful
    }
    else 
    { 
        nn->element=e; // Storing the elemnt read inside the the new node
        nn->next=q->top_stack; // Pointing the new node to the top of the stack
        q->top_stack=nn; // Changing the top of the stack
        return 1;
    }
}

提前谢谢你!

【问题讨论】:

  • 使用你的优先表。如果您想知道那是什么,请再返回一个家庭作业并实际研究您认为浪费时间的内容。 (不要指望do your homework for you)。

标签: c stack binary-tree expression-trees


【解决方案1】:

对于您正在使用的算法,操作数没有优先级。但在自下而上的 shift-reduce 解析器中,正如@WhozCraig 在下面这篇文章的评论中所说,它确实具有优先权。

操作数总是被压入操作数堆栈,并会被弹出 2 并使用运算符计算,然后作为单个操作数再次压入操作数堆栈。

对于您的公式: a / b + f – (c + d) * e – a * c

  • 一个
  • push 到操作数栈
  • 操作数:一个
  • 操作员

  • /

  • push 到运算符堆栈
  • 操作数:一个
  • 操作员:/

  • b

  • push 到操作数栈
  • 操作数:a b
  • 操作员:/

  • +

  • + / -> pop /, a & b -> a / b -> 推入操作数堆栈
  • + 推送到运算符堆栈
  • 操作数:(a / b)
  • 操作员:+

  • f

  • 推入操作数堆栈
  • 操作数:(a/b) f
  • 操作员:+

  • -

  • - + -> pop +, (a/b) & f -> (a/b) + f -> 推入操作数堆栈
  • 操作数:((a/b)+f)
  • 操作员:-

  • (

  • 推送到运算符堆栈
  • 操作数:((a/b)+f)
  • 操作员:-(

  • c

  • 推入操作数堆栈
  • 操作数:((a/b)+f) c
  • 操作员:-(

  • +

  • 推送到运算符堆栈
  • 操作数:((a/b)+f) c
  • 运算符:- (+

  • d

  • 推入操作数堆栈
  • 操作数:((a/b)+f) c d
  • 运算符:- (+

  • )

  • 直到'('弹出,将堆栈中的所有运算符一个一个弹出并使用2个操作数进行计算
  • -> pop +, c & d -> c + d -> 推入操作数栈
  • 操作数:((a/b)+f) (c+d)
  • 操作员:- (
  • -> pop (, 停止弹出操作符栈
  • 操作数:((a/b)+f) (c+d)
  • 操作员:-

  • *

  • * > - 推入操作栈
  • 操作数:((a/b) + f) (c + d)
  • 操作员:- *

  • e

  • * > - 推入操作数栈
  • 操作数:((a/b) + f) (c + d) e
  • 操作员:- *

  • -

  • - * pop *, (c + d) & e -> (c + d) * e -> 推入操作数堆栈
  • 操作数:((a/b)+f) ((c+d)*e)
  • 运营商:-
  • - - pop -, ((a/b)+f) & ((c+d)*e) -> ((a/b)+f) - ((c+d)*e) -> 推入操作数栈
  • 推 - 到运算符堆栈
  • 操作数:(((a/b)+f)-((c+d)*e))
  • 操作员:-

  • 一个

  • 推入操作数堆栈
  • 操作数:(((a/b)+f)-((c+d)*e)) a
  • 操作员:-

  • *

  • * > - 推入操作栈
  • 操作数:(((a/b)+f)-((c+d)*e)) a
  • 操作员:- *

  • c

  • 推入操作数堆栈
  • 操作数:(((a/b)+f)-((c+d)*e)) a c
  • 操作员:- *

  • 行尾

  • 一个一个地弹出堆栈中的所有运算符
  • pop *, a & c -> (a*c) -> push 到操作数栈
  • 操作数:(((a/b)+f)-((c+d)*e)) (a*c)
  • 运营商:-
  • pop -, (((a/b)+f)-((c+d)*e)) & (a*c) -> (((a/b)+ f)-((c+d)*e)) - (a*c) -> 推入操作数栈
  • 操作数:((((a/b)+f)-((c+d)*e))-(a*c))
  • 运营商

结果:((((a/b)+f)-((c+d)*e))-(a*c))

【讨论】:

  • "操作数没有优先级" - 注意:这不是普遍正确的(尽管在他/她的编译器类的这一点上可能适用于这个 OP)。在由 2D 优先级表驱动的自下而上 shift-reduce 解析器中,everything,包括 idconst,必须具有竞争优先级 (" take"、"yields"、"equals" 或 "error") 状态针对所有其他条目,包括 epsilon。在使用基于句柄的堆栈时,解析器自然捕获诸如(2 + 3 5) 之类的错误非常重要。不错的文章,顺便说一句。
  • 哦,我明白了。我从来没有了解过你之前说的自下而上的 shift-reduce 解析器。谢谢你的笔记。 :D
  • 可以在at this link 找到一份关于该主题的体面(我很少使用该术语)CS 级 PDF。它与您可能首先想到的优先级解析模型不同。每个都有非常明显的优点和缺点。有空的时候看看。警告:相当精通阅读语法。
  • 现在我想起了我的讲师教我的编译技术。实际上我在 1 年前就已经学会了,但我忘记了。哈哈哈。谢谢你的信息。 :D
猜你喜欢
  • 1970-01-01
  • 2014-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-08
  • 2013-04-21
相关资源
最近更新 更多