C 从堆栈创建抽象语法树

C 从堆栈创建抽象语法树,c,C,我正在做一个项目,我需要计算一个反向波兰符号表达式,或者将rpn表达式转换为中缀符号。为此,我将表达式的所有元素推到堆栈上,然后从堆栈中弹出每个元素并将其插入抽象语法树中。从那里,我将遍历树以完成求值和转换操作。这是我到目前为止所拥有的 #include <stdlib.h> #include <ctype.h> #include <stdio.h> #include <string.h> struct snode { char datum

我正在做一个项目,我需要计算一个反向波兰符号表达式,或者将rpn表达式转换为中缀符号。为此,我将表达式的所有元素推到堆栈上,然后从堆栈中弹出每个元素并将其插入抽象语法树中。从那里,我将遍历树以完成求值和转换操作。这是我到目前为止所拥有的

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

struct snode 
{
  char datum;
  struct snode* bottom;
};

struct tnode
{
  char datum;
  struct tnode* left;
  struct tnode*right;
};

struct snode* 
push(struct snode* stack, char x) {
  struct snode *S = (struct snode*)malloc(sizeof(struct snode));
  S->datum = x;
  S->bottom = stack;
  return S;
}

struct snode* 
pop(struct snode* stack) {
  struct snode *S;
  if (stack == NULL)
    return NULL;
  S = stack->bottom;
  free(stack);
  return S;
}

char
peek(struct snode* stack){
  return stack->datum;
}


struct tnode*
create_node(char x){
  struct tnode* tmp;
  tmp = (struct tnode*)malloc(sizeof(struct tnode));
  tmp->datum = x;
  tmp->right = NULL;
  tmp->left = NULL;
  return tmp;
}

void
print_table(struct tnode *AST){
  if(AST !=NULL){
    print_table(AST->left);
    printf("%c ", AST->datum);
    print_table(AST->right);
  }
}



struct tnode*
build_tree(struct snode *S)
{

  struct tnode* root;
  if (S == NULL)
    return NULL;

  char top = peek(S);

  if (top == 'A' || top == 'S' || top == 'X' || top == 'D' || top == 'M')
    {
      root = create_node(top);
      S = pop(S); 
      root->right = build_tree(S);
      S = pop(S);
      root->left = build_tree(S);
      return root;
    } 

  root= create_node(top);

  return root;
}


int
main(int argc, const char *argv[])
{

  int i = 1;
  struct tnode *tree = NULL;
  struct snode *stack = NULL;

  char value;
  while (argv[i]!= NULL)
    {
      value = argv[i][0];
      stack = push(stack, value);
      i++;
    }


  tree =  build_tree(stack);
  print_table(tree);
  printf("\n");

  return EXIT_SUCCESS;
}
输出

7 A 4 S 3
A 3 X 4
这是正确的。但是

./project 1 2 X 3 4 X A  
输出

7 A 4 S 3
A 3 X 4
这显然是不正确的。我很确定我的问题出在我的build_tree函数中,但我不知道如何以不同的方式构建一棵build_tree。 还有,当我有一个表达式,比如

./project 12 3 D 2 D
为什么会有这样的产出

1 D 3 D 2
而不是

12 D 3 D 2

谢谢你的帮助。任何关于如何更改代码以使项目的其余部分更简单的意见都将受到欢迎

主要问题是,当您在构建树函数中降低一个以上级别时,不会记住对堆栈的更新。例如,当您这样做时,root->right=构建树;在调用build_tree的上下文中弹出堆栈,堆栈实际上并没有在调用方的上下文中弹出

我建议您根据以下内容更改您的功能:

void
pop(struct snode **stack) {
  struct snode *S;
  if (*stack == NULL)
    return;

  S = (*stack)->bottom;
  free(*stack);
  *stack = S;
}


struct tnode*
build_tree(struct snode **S)
{

  struct tnode* root;
  if (*S == NULL)
    return NULL;

  char top = peek(*S);

  if (top == 'A' || top == 'S' || top == 'X' || top == 'D' || top == 'M')
    {
      root = create_node(top);
      pop(S); 
      root->right = build_tree(S);
      pop(S);
      root->left = build_tree(S);
      return root;
    } 

  root = create_node(top);

  return root;
}

int
main(int argc, const char *argv[])
{
  ...

  tree =  build_tree(&stack);

  ...
}
如果将printf调用添加到peek中,并在其中输出访问的堆栈节点的数据,则差异会变得更加明显

对于您的另一个错误,./project 12 3 D 2 D不起作用,12被替换为1,我建议您使用atoi函数将字符串转换为整数,而不仅仅是value=argv[I][0]。您可以测试value是否是一个数字,如果是的话,随后测试value=atoiragv[i]

此外,正如前面所述,您需要定义运算符优先级规则,并根据需要添加括号。最简单的方法是在每次向左移动之前添加一个左括号,在每次从右侧返回之后添加一个右括号

编辑

还要注意的是,1 2 X 3 4 X A*不是有效的rpn,而1 2 X 3 4 X A是因为extra*没有匹配的right运算符

编辑2

支持多位数的解决方案可以是使用字符串而不是字符来表示所有令牌。您需要在以下位置用char*更改所有出现的char:

struct snode和struct tnode的定义 push和create_节点的参数 peek的返回值。 构建树中主和顶部的变量值。 此外,您需要将value=argv[i][0]更改为value=argv[i]我还建议将常量限定符从argv参数删除为main,除非您希望常量正确。您还需要更改运算符相等性检查。例如,您可以执行以下操作:

int
is_operator(char *tok)
{
  return !strcmp(tok, "A") || !strcmp(tok, "S") || !strcmp(tok, "X") || !strcmp(tok, "D") || !strcmp(tok, "M");
}
然后简单地在构建树中编写if is_operator top


最后,,您需要将printf格式字符串从%c更改为%s。

您不需要在中缀符号中使用大括号来控制表达式求值顺序吗?现在,我刚刚到达一个点,我知道树正在正确构建@NikolaiNFetissov1 vs 12在您的上一个示例中很简单-您只使用了每个argv[i]。第一个错误是由于在构建树函数的if语句中缺少check for*运算符。这是我的错误。我编辑了我的文章,所以没有额外的*我也对你关于如何解决我遇到的字符串问题的解释感到困惑。是的,我现在知道你需要做额外的更改。如果希望支持多位数,则不能再简单地将令牌表示为字符。也许只使用字符串会更好?如果是这样,您需要通过调用strcmp更改运算符的相等性测试。我更新了我的答案,解释了如何使用字符串。感谢您的帮助@ErlendGraff