二叉树的前中后序遍历以及表达式树

 

  昨天数据结构课布置了上机实验,要求递归方式建立表达式二叉树,输出树的前中后序遍历的结果,并计算表达式的值。网上其他人的做法无非就是先求出后缀表达式,然后后序遍历的方式+栈建立二叉树,可是本题的要求是递归方式,所以我的方法就是求出前缀表达式,用前序遍历的方法可以递归建立二叉树,最后用后序遍历的方式求解表达式树。

  举个栗子:表达式:1 + 2 * (3 - 4) - 5 / 6,那么它的前缀表达式就是:- + 1 * 2 - 3 4 / 5 6,那么可以建立二叉树,如图:

  最后,附上代码

/************************************************
* Author        :Running_Time
* Created Time  :2015/10/29 星期四 16:12:53
* File Name     :BT.cpp
 ************************************************/

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
#include <iomanip>
using namespace std;

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
typedef long long ll;
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const double EPS = 1e-10;
const double PI = acos (-1.0);
/*
    表达式求值,逆波兰式(后缀表达式)算法
    输入(可以有空格,支持小数,实现'+-/*%'): ((1+2)*5+1)/4=
    注意:取模一定是要整型,实现版本数字全是double,强制类型转换可能倒置错误
    转换为后缀表达式: 得到:1 2 + 5 * 1 + 4 / =
    计算后缀表达式:得到:4.00
*/
bool is_digit(char ch)  {
	return '0' <= ch && ch <= '9';
}
struct Exp  {
    stack<char> op;
    stack<double> num;
    bool error;

    int prior(char ch)  {                           //运算符的优先级
        switch (ch) {
            case '+':
            case '-': return 1;
            case '*':
            case '%':
            case '/': return 2;
            default:  return 0;
        }
    }
    string get_prefix(string s)	{					//中缀表达式转变前缀表达式
        while (!op.empty ())	op.pop ();
        op.push ('#');
        string ret = "";
        int len = s.length (), i = len - 1;
        while (i >= 0)	{
			if (s[i] == ' ' || s[i] == '=')	{
				i--;	continue;
			}
			else if (s[i] == ')')	{
				op.push (s[i--]);
			}
			else if (s[i] == '(')	{
				while (op.top () != '#' && op.top () != ')')	{
					ret += op.top ();	ret += ' ';
					op.pop ();
				}
				op.pop ();	i--;
			}
			else if (s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/' || s[i] == '%')  {
                while (prior (op.top ()) > prior (s[i]))    {
                    ret += op.top ();	ret += ' ';
                    op.pop ();
                }
                op.push (s[i--]);
            }
            else    {
                while (is_digit (s[i]) || s[i] == '.')  {
                    ret += s[i--];
                }
                ret += ' ';
            }
        }
        while (op.top () != '#') {
            ret += op.top ();	ret += ' ';
            op.pop ();
        }
        reverse (ret.begin (), ret.end ());
        return ret;
    }
    double cal(double a, double b, char ch) {
        if (ch == '+')  return a + b;
        if (ch == '-')  return a - b;
        if (ch == '*')  return a * b;
        if (ch == '%')  return (int)((int)a % (int)b);
        if (ch == '/')  {
            if (b != 0) return a / b;
            error = true;   return 0;
        }
        return 0;
    }
    string get_postfix(string s)    {               //中缀表达式转变后缀表达式
        while (!op.empty ())    op.pop ();
        op.push ('#');
        string ret = "";
        int len = s.length (), i = 0;
        while (i < len)    {
            if (s[i] == ' ' || s[i] == '=')    {
                i++;    continue;
            }
            else if (s[i] == '(')    {
                op.push (s[i++]);
            }
            else if (s[i] == ')')   {
                while (op.top () != '(')    {
                    ret += op.top ();   ret += ' ';
                    op.pop ();
                }
                op.pop ();  i++;
            }
            else if (s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/' || s[i] == '%')  {
                while (prior (op.top ()) >= prior (s[i]))    {
                    ret += op.top ();   ret += ' ';
                    op.pop ();
                }
                op.push (s[i++]);
            }
            else    {
                while (is_digit (s[i]) || s[i] == '.')  {
                    ret += s[i++];
                }
                ret += ' ';
            }
        }
        while (op.top () != '#') {
            ret += op.top ();   ret += ' ';
            op.pop ();
        }
        ret += '=';
        return ret;
    }
    double solve(string str)    {                   //计算后缀表达式
        string s = get_postfix (str);
        while (!num.empty ())   num.pop ();
        error = false;
        int len = s.length (), i = 0;
        while (i < len)  {
            if (s[i] == ' ' || s[i] == '=') {i++;   continue;}
            else if (s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/' || s[i] == '%')  {
                double a = num.top ();  num.pop ();
                double b = num.top ();  num.pop ();
                num.push (cal (b, a, s[i]));    i++;
            }
            else  {
                double x = 0;
                while (is_digit (s[i])) {
                    x = x * 10 + s[i] - '0';    i++;
                }
                if (s[i] == '.')    {
                    double k = 10.0, y = 0;
                    i++;
                    while (is_digit (s[i])) {
                        y += ((s[i] - '0') / k);
                        i++;    k *= 10;
                    }
                    x += y;
                }
                num.push (x);
            }
        }
        return num.top ();
    }
}E;
typedef struct BT	{
    char op;
    double data;
    BT *lch, *rch;
}node, *btree;

void print(btree p)	{
	if (! (p -> lch) && ! (p -> rch))	{
		cout << fixed << setprecision (1) << p -> data << " ";
//		cout << p -> data << " ";
	}
	else	cout << p -> op << " ";
}

int i;

double get_num(string s)	{
	double x = 0;
	while (is_digit (s[i])) {
		x = x * 10 + s[i] - '0';    i++;
	}
	if (s[i] == '.')    {
		double k = 10.0, y = 0;
		i++;
		while (is_digit (s[i])) {
			y += ((s[i] - '0') / k);
			i++;    k *= 10;
		}
		x += y;
	}
	return x;
}

void creat(btree &T, string s)	{
	T = new node;
	while (i < s.length () && (s[i] == ' ' || s[i] == '.'))	i++;
	if (i >= s.length ())	{
		T -> lch = T -> rch = NULL;	return ;
	}
	if (is_digit (s[i]))	{
        T -> data = get_num (s);
		T -> lch = T -> rch = NULL;
		i++;	return ;
	}
	else	{
		T -> op = s[i];
		i += 2;
		creat (T -> lch, s);
		creat (T -> rch, s);
	}
}

void pre_order(btree T)	{		//前序遍历
    if (T != NULL)	{
		print (T);
		pre_order (T -> lch);
		pre_order (T -> rch);
    }
}

void in_order(btree T)	{		//中序遍历
	if (T != NULL)	{
		in_order (T -> lch);
		print (T);
		in_order (T -> rch);
	}
}

void post_order(btree T)	{	//后序遍历
	if (T != NULL)	{
		post_order (T -> lch);
		post_order (T -> rch);
		print (T);
	}
}

double cal_tree(btree &T)	{
    if (T != NULL)	{
		if (! (T -> lch) && ! (T -> rch))	{
			return T -> data;
		}
		else	return E.cal (cal_tree (T -> lch), cal_tree (T -> rch), T -> op);
    }
}

int main(void)    {
    ios::sync_with_stdio (false);
    int T;  cin >> T;
    string str; getline (cin, str);
    while (T--) {
        getline (cin, str);
        string pre = E.get_prefix (str), post = E.get_postfix (str);
        cout << "前缀表达式:" << pre << endl;
        cout << "后缀表达式:" << post << endl;

		btree tree;
		i = 0;		//全局变量记录string下标,递归建立表达式树
		creat (tree, pre);
		cout << "前序遍历:";	pre_order (tree);	cout << endl;
		cout << "中序遍历:";	in_order (tree);	cout << endl;
		cout << "后序遍历:";	post_order (tree);	cout << endl;
		cout << "后缀表达式计算结果:" << fixed << setprecision (6) << E.solve (str) << endl;
		cout << "表达式树结果:" << fixed << setprecision (6) << cal_tree (tree) << endl << endl;
    }

    return 0;
}
/*
测试样例:
1000
1 + 2
1 + 2 - 3 / 4 * 5
1 + 2 * (3 - 4) - 5 / 6
1+2*3-4/(5-6*7+8)/9
1-2+3*4%(5+6-7/8)+9
1+(2-3)*4*(5-6+7/8)/9
11+(22-33)*44*(55-6+7/8)/9
19+(28-37)*46*(55-64+73/82)/91
1.2+(2.421-3.3123)*4.0*(5.42342-6+7.2*8.13)/9.1321
*/

  

 

转载于:https://www.cnblogs.com/Running-Time/p/4922670.html

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值