有一个数值表达式,生成树,并以三种遍历方式输出树,最后求值
表达式中只有数字、加、减、乘、除和括号,要求用二叉树解决,要可以计算表达式的值……
/*
你是指数值表达式求值吗?是的话就看看吧……
这是去年的二月份写的了……时间过得真快……
呃……跑题了……
这份是精简的,原来的包括阶乘、幂、解析函数啊什么的、不过对于你的题目要求有点过于庞大……
如果要原版的话就追问提出吧……
嗯……这份代码为了计算准确是以最右面的同级运算符作为建树的起点、所以生成的树比较特殊……
前序遍历和后序遍历也不是标准的波兰式、逆波兰式了……
当然中序遍历也不是原来的式子了,这主要决定于建树时的方法了……
Linux GCC 3。
4。5 下运行通过……
*/
//#include // 要 Linux 或 MS-WIN MinGW 的话注释掉
#include
#include
using namespace std;
#define invalid_argument // 要 MS-WIN MS-VC 的话注释掉
// note:
// 2009-1-1 立项
// 2009-1-27 复工
// 2009-2-6 添加角、弧、梯度制度转换
// 2009-2-7 beta 1
// 基本的四则运算
#define OPERATORS_PLUS 0x000001
#define OPERATORS_MINUS 0x000002
#define OPERATORS_MUTIPLE 0x000003
#define OPERATORS_DIVIDE 0x000004
class expression
{
private:
public:
double m_value; // 该节点经计算后的结果
int m_operator; // 该节点操作符
expression *m_left; // 左子树
expression *m_right; // 右子树
private:
std::string delete_bracket( const std::string p_exp ); //如果如果表达式处于括号内,则去掉括号
bool make_tree( const std::string p_exp ); // 生成二叉树,用下面的函数作为生成条件
bool find_plus_minus( char *p_pexp ); // 将一个表达式分解成三部分,第一部分包含第一个加数或被减数,第二部分为操作符[ -],余下的做为第三部分
bool find_mutiple_divide_mod( char *p_pexp ); // 将一个因式分解成三部分,第一部分包含第一个因数或被除数,第二部分为操作符[*/%],余下的做为第三部分
// 将操作符字符串转换为操作符常量
inline int operatorstr2type( const char *p_pstr, int &p_operator_length );
inline int operatorstr2type( const char *p_pstr );
public:
expression( void );
expression( const std::string p_exp );
double get_result( void ); // 得到结果
double get_result( const std::string p_exp ); // 计算并返回结果
virtual ~ expression( void );
void release( );
void parse( const std::string p_exp );
int preorder( void );
int inorder( void );
int postorder( void );
public:
};
expression::expression( void )
{
m_left = NULL;
m_right = NULL;
m_value = 0。
0f;
m_operator = 0;
}
expression::~expression( void )
{
release( );
}
void expression::release( void )
{
if( m_left )
{
delete m_left;
m_left = 0;
}
if( m_right )
{
delete m_right;
m_right = 0;
}
}
expression::expression( const std::string p_exp )
{
m_left = NULL;
m_right = NULL;
m_value = 0。
0f;
m_operator = 0;
parse( p_exp );
}
void expression::parse( const std::string p_exp )
{
// 解析表达式
release( );
if( strlen( p_exp。
c_str( ) ) == 0 )
{
// 若是空串,则值为0,返回
m_value = 0。0f;
return;
}
if( !make_tree( p_exp ) ) // 建树,检查是否可以被分解成两个部分,如果可分,则分解过程中不断产生新的子树
{
// 若不可分,应该就是数值了,此时整个表达式有可能在括号里面,所以应该先去括号再取值。
m_value = atof( delete_bracket( p_exp )。c_str( ) );
}
}
std::string expression::delete_bracket( const std::string p_exp )
{
// 去括号
char ch = 0;
int pos = 0;
int bracket_count = 0; // 括号计数器,遇'('加1,遇')'减1
if( p_exp[0] != '(' )
{
while( p_exp[pos] )
{
ch = p_exp[pos ];
if( ( ch '9' && ch 'Z' ) ) && ( ch != ' ' && ch != '-' && ch != '*' && ch != '/' && ch != '\' && ch != '%' && ch != '^' && ch != '!' && ch != '(' && ch != ')' && ch != '。
' && ch != ' ' ) )
throw invalid_argument( string( "表达式中的有错误!在 " ) ch string( " 附近" ) );
}
return p_exp; // 最左边不是左括号,所以不能去括号
}
pos = 0;
while( bracket_count == 0 )
{
// 找到第一个左括号
ch = p_exp[pos ];
if( ch == 0 )
return p_exp; // 没有找到左括号
if( ch == '(' )
bracket_count ; // 找到左括号,结束循环
}
// 现在肯定有左括号'(',并且括号计数值是1,现在找右括号
while( bracket_count != 0 )
{
ch = p_exp[pos ];
if( ch == 0 ) // 没有找到匹配的括号
throw invalid_argument( string( "表达式中的括号不匹配!" ) );
if( ch == '(' )
bracket_count ;
if( ch == ')' )
bracket_count--;
}
if( p_exp[pos] != 0 )
// 找到了右括号,而且没有到结尾,说明表达式不全在一对括号内,这时不应该去括号,而应该返回原表达式串
return p_exp;
else
// 整个表达式全在一对括号内,去掉两端的括号,返回去掉两端括号之后的表达式串
return p_exp。
substr( 1, p_exp。length( ) - 2 );
}
bool expression::make_tree( std::string p_exp )
{
// 开始建树
size_t len = strlen( p_exp。
c_str( ) );
if( len == 0 )
{
// 表达式为空时
m_value = 0。0;
return true; // 已完成建树的过程
}
size_t start = 0;
// 去空格
while( p_exp[start] == ' ' )
start ;
while( p_exp[len - 1] == ' ' )
len--;
p_exp = p_exp。
substr( start, len - start ); // 去掉空格之后的新串
return find_plus_minus( ( char * ) delete_bracket( p_exp。c_str( ) )。
c_str( ) );
// 加减试下
}
bool expression::find_plus_minus( char *p_pexp )
{
int bracket_count = 0; // 括号计数器
char *pch = p_pexp; //用于遍历表达式
char *pop = 0; // 指向找到的操作符
while( *pch )
{
if( *pch == '(' )
{
bracket_count ;
while( bracket_count > 0 && ( *pch ) )
{
pch ;
if( *pch == ')' )
--bracket_count;
if( *pch == '(' )
bracket_count;
} // 跳过括号
}
else if( *pch == ' ' || *pch == '-' )
pop = pch; // 指向最后一个操作符,生成子二叉树时,前面的都在左子树上
pch ;
}
if( pop )
{
// 找到了加或减操作符,以操作符为界分为左右两部分
std::string sl, sr;
sl。
append( p_pexp, pop - p_pexp );
sr。append( pop 1, pch - pop );
m_operator = operatorstr2type( pop ); // 设置该节点的操作符
if( this->m_operator == -1 )
throw invalid_argument( string( "表达式中有错误!在 / - 附近" ) );
m_left = new expression( sl ); // 生成左子树
m_right = new expression( sr ); // 生成右子树
return true; //返回真值, 表示已完成建树的过程
}
else
// 没有找到加减运算符,再找乘除模运算符,并返回它的结果
return find_mutiple_divide_mod( p_pexp );
}
bool expression::find_mutiple_divide_mod( char *p_pexp )
{
int bracket_count = 0; // 括号计数器
char *pch = p_pexp; //用于遍历表达式
char *pop = 0; // 指向找到的操作符
while( *pch )
{
if( *pch == '(' )
{
bracket_count ;
while( bracket_count > 0 && ( *pch ) )
{
pch ;
if( *pch == ')' )
--bracket_count;
if( *pch == '(' )
bracket_count;
} // 跳过括号
}
else if( *pch == '*' || *pch == '/' || *pch == '%' || *pch == '\' )
pop = pch; // 指向最后一个操作符,生成子二叉树时,前面的都在左子树上
pch ;
}
if( pop )
{
// 找到了乘、除或模操作符,以操作符为界分为左右两部分
string sl, sr;
sl。
append( p_pexp, pop - p_pexp );
sr。append( pop 1, pch - pop );
m_operator = operatorstr2type( pop ); // 设置该节点的操作符
if( this->m_operator == -1 )
throw invalid_argument( string( "表达式中有错误!在*//\/%附近" ) );
m_left = new expression( sl ); // 生成左子树
m_right = new expression( sr ); // 生成右子树
return true; // 返回真值, 表示已完成建树的过程
}
else
return false;
}
double expression::get_result( void )
{ // HUGE_VAL
// 也就是简单的中序遍历就可以了
switch ( this->m_operator )
{
case OPERATORS_PLUS:
m_value = m_left->get_result( ) m_right->get_result( );
break;
case OPERATORS_MINUS:
m_value = m_left->get_result( ) - m_right->get_result( );
break;
case OPERATORS_MUTIPLE:
m_value = m_left->get_result( ) * m_right->get_result( );
break;
case OPERATORS_DIVIDE:
m_value = m_left->get_result( ) / m_right->get_result( );
break;
default:
break;
}
return m_value;
}
// 直接计算给出的表达式的值,并返回
double expression::get_result( const std::string p_pexp )
{
parse( p_pexp );
return get_result( );
}
inline int expression::operatorstr2type( const char *p_pstr, int &p_operator_length )
{
// 四则运算以及模、幂、阶乘
if( *p_pstr == ' ' )
{
p_operator_length = 1;
return OPERATORS_PLUS;
}
else if( *p_pstr == '-' )
{
p_operator_length = 1;
return OPERATORS_MINUS;
}
else if( *p_pstr == '*' )
{
p_operator_length = 1;
return OPERATORS_MUTIPLE;
}
else if( *p_pstr == '/' )
{
p_operator_length = 1;
return OPERATORS_DIVIDE;
}
return -1;
}
inline int expression::operatorstr2type( const char *p_pstr )
{
int agent = 0;
return this->operatorstr2type( p_pstr, agent );
}
int expression::preorder( void )
{
static char op[][2] = { "", " ", "-", "*", "/" };
if( this->m_operator )
cout m_operator] m_value preorder( );
if( m_right )
m_right->preorder( );
return 0;
}
int expression::inorder( void )
{
if( m_left )
m_left->preorder( );
static char op[][2] = { "", " ", "-", "*", "/" };
if( this->m_operator )
cout m_operator] m_value preorder( );
return 0;
}
int expression::postorder( void )
{
if( m_left )
m_left->preorder( );
if( m_right )
m_right->preorder( );
static char op[][2] = { "", " ", "-", "*", "/" };
if( this->m_operator )
cout m_operator] m_value << ' ';
return 0;
}
int main( int argc, char *argv[] )
{
char exp[] = "1 2 - 3";
expression exptree;
exptree。
parse( exp );
cout << "Pre-order: ";
exptree。preorder( );
cout << endl << "In-order: ";
exptree。
inorder( );
cout << endl << "Post-order: ";
exptree。postorder( );
cout << endl << exp << " = " << exptree。
get_result( );
return 0;
}。
问:身体出现了异常情况,好害怕哦不会是癌的征兆吧?我这个月例假结束后,隔了大概三天后...
答:不好这么说.疾病有很多种,也许是宫颈糜烂呢?或者阴道炎啊什么的,但是不管是哪种病,一定要赶紧去医院.不要讳疾忌医啊.很多病就是因为耽误了所以才不好治的.你这样忐...详情>>