• 表达式转表达式二叉树


    表达式树

    二叉树是表达式处理的常用工具,例如,a+b*(c-d)-e/f可以表示成如下所示的二叉树

    其中,每个非叶子节点表示一个运算符,左子树是第一个运算数对应的表达式,右子树是第二个表达式对应的表达式。每个叶子节点都是数。

    其在空间利用上也非常高效,节点数等于表达式的长度。

    表达式转二叉树

    lrj说方法有很多种,下面介绍他讲的一种:找到“最后计算”的运算符(它是整个表达式树的根),然后递归处理左右两边。

     1 const int maxn = 1000 + 10; 
     2 char str[maxn];
     3 int lch[maxn + 1], rch[maxn + 1]; char op[maxn + 1];     //每个结点的左右子结点编号和字符
     4 int nc = 0;         //结点数 
     5 int build_tree(char* s, int x, int y) 
     6 {  
     7     int i, c1=-1, c2=-1, p=0;  
     8     int u; 
     9     if(y-x == 1)   //仅一个字符,建立单独结点 
    10     {        
    11         u = ++nc;    
    12         lch[u] = rch[u] = 0; 
    13         op[u] = s[x];   
    14         return u;
    15      } 
    16 
    17      for (i = x; i < y; i++)   //寻找根节点的位置
    18      {
    19          switch (s[i]) 
    20          {
    21             case '(':  p++; break;     
    22             case ')':  p--; break;      
    23             case '+':
    24             case '-':  if (!p) c1 = i; break;      
    25             case '*': 
    26             case '/':  if (!p) c2 = i; break;
    27          }
    28      }  
    29     if (c1 < 0) c1 = c2;     //找不到括号外的加减号,就用乘除号  
    30     if(c1 < 0) return build_tree(s, x+1, y-1);     //整个表达式被一对括号括起来  
    31     u = ++nc;  
    32     lch[u] = build_tree(s, x, c1); 
    33     rch[u] = build_tree(s, c1+1, y);  
    34     op[u] = s[c1];  
    35     return u;
    36 }

    前缀式、中缀式、后缀式

    前缀表达式和后缀表达式分别对应表达式树前序和后序遍历的结果,如果不考虑括号,中缀表达式对应表达式树中序遍历的结果。

     1 //中序遍历
     2 void InOrder(int root)
     3 {
     4     if (lch[root] > 0)  InOrder(lch[root]);
     5     printf("%c ", op[root]);
     6     if (rch[root] > 0)  InOrder(rch[root]);
     7 }
     8 
     9 //后序遍历
    10 void PostOrder(int root)
    11 {
    12     if (lch[root] > 0)  PostOrder(lch[root]);
    13     if (rch[root] > 0)  PostOrder(rch[root]);
    14     printf("%c ", op[root]);
    15 }

    表达式求值

    有了表达式树求值就非常简单了,先求左子树的值,再求右子树值,然后根据根节点的运算符计算最终的值。整个过程采用递归求解。

    (注意!!这种方法只能求个位数表达式的值)

     1 //根据表达式二叉树求值
     2 int cal(int root)
     3 {
     4     int ans = 0;
     5     char ch = op[root];
     6     if (isdigit(ch))  return ch - '0';
     7     switch (ch)
     8     {
     9     case '+':  ans = cal(lch[root]) + cal(rch[root]); break;
    10     case '-':  ans = cal(lch[root]) - cal(rch[root]); break;
    11     case '*':  ans = cal(lch[root]) * cal(rch[root]); break;
    12     case '/':  ans = cal(lch[root]) / cal(rch[root]); break;
    13     }
    14     return ans;
    15 }

    打印二叉树(括号表达法)

    root(lch,rch)像这样的格式,其中lch,rch本身也是这样的格式(递归定义)。整个过程类似于先序遍历,先打印根节点,再打印左子树,再打印右子树。

    注意格式,如果缺少左、右子树用空格代替(如root( ,rch)),如果都没有,则括号也省掉。

    //打印表达式二叉树
    void PrintTree(int root)
    {
        int flag = 0;        //标记是否有左右子树
        printf("%c", op[root]);
        if (lch[root] > 0)  flag += 1;
        if (rch[root] > 0)  flag += 2;
        if (flag == 0)  return;
        if (flag == 1)        //只有左子树
        {
            printf("(");
            PrintTree(lch[root]);
            printf(", )");
        }
        if (flag == 2)        //只有右子树
        {
            printf("( ,");
            PrintTree(rch[root]);
            printf(")");
        }
        if (flag == 3)        //左右子树都有
        {
            printf("(");
            PrintTree(lch[root]);
            printf(",");
            PrintTree(rch[root]);
            printf(")");
        }
    }

    最一个加一个认真写的 胡乱写的能实现嵌套括号、多位数相加减乘除的完整代码

      1 #include<stdio.h>
      2 #include<string>
      3 
      4 const int maxn = 1000 + 10; 
      5 char expr[maxn];        //原表达式
      6 int str[maxn];            //转换后的表达式
      7 int lch[maxn + 1], rch[maxn + 1],op[maxn + 1];     //每个结点的左右子结点编号和字符
      8 bool is_alpha1[maxn], is_alpha2[maxn];        //是否为操作符或括号,前者对s数组,后者对op数组
      9 int nc = 0;         //结点数 
     10 int cnt = 0;        //转换后字符串的长度
     11 
     12 // 把表达式exp转化成参数形式,并存到str中
     13 void analyse(char* expr)
     14 {
     15     int len = strlen(expr);
     16     int i = 0;
     17     while(i < len)
     18     {
     19         if (!isdigit(expr[i]))
     20         {
     21             str[cnt] = expr[i++];
     22             is_alpha1[cnt++] = true;
     23         }
     24         else
     25         {
     26             int tmp = 0;
     27             while (isdigit(expr[i]))
     28             {
     29                 tmp = tmp * 10 + expr[i] - '0';
     30                 i++;
     31             }
     32             str[cnt] = tmp;
     33             is_alpha1[cnt++] = false;
     34         }
     35     }
     36 }
     37 
     38 //表达式转表达式树
     39 int build_tree(int* s, int x, int y) 
     40 {  
     41     int i, c1=-1, c2=-1, p=0;  
     42     int u; 
     43     if(y-x == 1)   //仅一个字符,建立单独结点 
     44     {        
     45         u = ++nc;    
     46         lch[u] = rch[u] = 0; 
     47         op[u] = s[x];   
     48         if (is_alpha1[x])  is_alpha2[u] = true;
     49         return u;
     50      } 
     51 
     52      for (i = x; i < y; i++)   //寻找根节点的位置
     53      {
     54          if(s[i] == '(' && is_alpha1[i])   p++;
     55          if(s[i] == ')' && is_alpha1[i])   p--;
     56          if((s[i] == '+' || s[i] == '-') && is_alpha1[i])   if (!p) c1 = i;
     57          if((s[i] == '*' || s[i] == '/') && is_alpha1[i])    if (!p) c2 = i;
     58      }  
     59     if (c1 < 0) c1 = c2;     //找不到括号外的加减号,就用乘除号  
     60     if(c1 < 0) return build_tree(s, x+1, y-1);     //整个表达式被一对括号括起来  
     61     u = ++nc;  
     62     lch[u] = build_tree(s, x, c1); 
     63     rch[u] = build_tree(s, c1+1, y);  
     64     op[u] = s[c1];  
     65     if (is_alpha1[c1])  is_alpha2[u] = true;
     66     return u;
     67 }
     68 
     69 //先序遍历
     70 void PreOrder(int root)
     71 {
     72     if(!is_alpha2[root])  printf("%d ", op[root]);
     73     else  printf("%c ", op[root]);
     74 
     75     if (lch[root] > 0)  PreOrder(lch[root]);
     76     if (rch[root] > 0)  PreOrder(rch[root]);
     77 }
     78 
     79 //中序遍历
     80 void InOrder(int root)
     81 {
     82     if (lch[root] > 0)  InOrder(lch[root]);
     83 
     84     if (!is_alpha2[root])  printf("%d ", op[root]);
     85     else  printf("%c ", op[root]);
     86 
     87     if (rch[root] > 0)  InOrder(rch[root]);
     88 }
     89 
     90 //后序遍历
     91 void PostOrder(int root)
     92 {
     93     if (lch[root] > 0)  PostOrder(lch[root]);
     94     if (rch[root] > 0)  PostOrder(rch[root]);
     95 
     96     if (!is_alpha2[root])  printf("%d ", op[root]);
     97     else  printf("%c ", op[root]);
     98 }
     99 
    100 //根据表达式二叉树求值
    101 int cal(int root)
    102 {
    103     int ans = 0;
    104     int ch = op[root];
    105     if (!is_alpha2[root])  return ch;
    106     switch (ch)
    107     {
    108     case '+':  ans = cal(lch[root]) + cal(rch[root]); break;
    109     case '-':  ans = cal(lch[root]) - cal(rch[root]); break;
    110     case '*':  ans = cal(lch[root]) * cal(rch[root]); break;
    111     case '/':  ans = cal(lch[root]) / cal(rch[root]); break;
    112     }
    113     return ans;
    114 }
    115 
    116 //打印表达式二叉树
    117 void PrintTree(int root)
    118 {
    119     int flag = 0;        //标记是否有左右子树
    120     if (!is_alpha2[root])  printf("%d", op[root]);
    121     else  printf("%c", op[root]);
    122 
    123     if (lch[root] > 0)  flag += 1;
    124     if (rch[root] > 0)  flag += 2;
    125     if (flag == 0)  return;
    126     if (flag == 1)        //只有左子树
    127     {
    128         printf("(");
    129         PrintTree(lch[root]);
    130         printf(", )");
    131     }
    132     if (flag == 2)        //只有右子树
    133     {
    134         printf("( ,");
    135         PrintTree(rch[root]);
    136         printf(")");
    137     }
    138     if (flag == 3)        //左右子树都有
    139     {
    140         printf("(");
    141         PrintTree(lch[root]);
    142         printf(",");
    143         PrintTree(rch[root]);
    144         printf(")");
    145     }
    146 }
    147 
    148 int main()
    149 {
    150     printf("表达式:");
    151     scanf("%s", expr);
    152 
    153     analyse(expr);   //转化
    154 
    155     
    156     build_tree(str, 0, cnt);        //建树
    157 
    158     int root = 1;                            
    159     printf("先序遍历:"); PreOrder(root); printf("
    ");            //三种遍历
    160     printf("中序遍历:"); InOrder(root); printf("
    ");
    161     printf("后序遍历:"); PostOrder(root); printf("
    ");
    162 
    163     printf("表达式二叉树:"); PrintTree(root); printf("
    ");        //打印表达式二叉树
    164 
    165     int ans;
    166     ans = cal(root);                //表达式求值
    167     printf("表达式值:%d
    ", ans);
    168 
    169     return 0;
    170 }
  • 相关阅读:
    使用 jquery 的 上传文件插件 uploadify 3.1 配合 java 来做一个简单的文件上次功能。并且在界面上有radio 的选择内容也要上传
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
  • 原文地址:https://www.cnblogs.com/lfri/p/9985993.html
Copyright © 2020-2023  润新知