您的位置:首页 > 其它

ACM解题总结——HihoCoder1155

2016-03-04 13:27 435 查看
题目来源:
    HihoCoder1155

题目要求:
    题目要求给定一个Lisp语句,求解表达式的值。
    Lisp语句的表达式格式有如下几种:
    (1) 单独的一个非负整数是一个合法的表达式,如:2。
    (2) 单独的一个布尔值是一个合法的表达式,其值只有2种:true 和 false。
    (3) 定义变量。变量的名称由不超过10个的小写英文字母组成,true,false,let,if为保留字,不能作为变量名,该表达式的值为变量的绑定值,如果变量没有绑定,则表达式非法,程序输出:Unbound Identifer。
    (4) 算术运算。包括加减乘除,格式为:( + x y )、( - x y )、( * x y )、( / x y )。其中 x y 均为合法的表达式,并且只有 x y 的值的结果均为数字时,该表达式才合法,否则,表达式非法,程序输出:Type Mismatch。另外,如果除法表达式中的除数是0,则该表达式非法,程序输出:Division By Zero。
    (5) 分支表达式:if。格式为:( if a b c )。其中:a b c 均为合法的表达式。a的表达式的值必须为布尔值,否则,该表达式非法,程序输出:Type Mismatch。如果表达式a的值为true,则该表达式的值为表达式b的计算值,否则,该表达式的值为表达式c的计算值。
    (6) let表达式。let表达式的作用是对变量绑定一个值。格式为:( let ( x a ) b ),其中 x 一定为变量, a 是合法的表达式,该表达式的值是把 x = a 代入到b中后,表达式b的计算值。例如:表达式:( let ( x 2 ) ( + x 1 ) )的值是3;另外在包含let表达式嵌套的表达式中,如果对相同的变量绑定多次,则最层的绑定有效,如:表达式 ( let ( x
1 ) ( let (x 2) ( + x 1 ) ) ) 的计算值是3而不是2。
    (7)比较运算。格式为 ( < x y )、 ( > x y )、( = x y )。其中 x y 都是合法的表达式,并且计算值必须为数字,否则,该表达式非法,程序输出:Type
Mismatch。根据x y的值的大小关系确定该表达式的值为true或false。
    以上是题目中用到的Lisp表达式的语法。
    给定的输入数据保证语法正确,仅存在逻辑错误。

解答:
    本题的要求其实是要编写一个简单的编译器。代码量比较大,但难度不算太难。基本的解答思路是根据输入的表达式构建语法树。然后遍历语法树后,整个表达式的值就存储在语法树的根节点中。比较好的一点是:题目中所有的语法都是“前缀语法”,即操作符在操作数的前面。这样程序处理数据的顺序就是表达式的读取顺序——从左到右。首先说明语法树的构建方式。
    根据题目中的语法的描述,需要用到的语法树的节点有如下的几种:
    (1) 数值: 这是最简单的节点,没有子节点,在语法树中是叶子节点。节点的值就是数值本身,存储在节点内。如下:
    


     (2)布尔值:这也是最简单的节点,在语法树中也是叶子节点。节点的值就是布尔值本身,存储在节点内。如下:
    

 
    (3)变量:变量有变量名和变量值两个属性,但表达式的值仅和变量的值有关,因此变量也是一个叶子节点,节点中存储变量的名称和变量值:
    

 
    (4)算术计算。算术运算表达式的值需要先计算两个子表达式 x y 的值,再计算整个表达式的值,因此它有两个子节点,分别代表子表达式 x 和 y。如下:
     


    (4)分支表达式:表达式( if a b c ) 的值由表达式 a b c 的值决定,因此if节点具有3个子节点,分别代表表达式a b c,如下:
    

 
    (6)let 表达式:let表达式有三个字表达式:变量x,赋值表达式a,以及求值表达式b,因此它也有3个子节点,分别代表变量、赋值表达式a、求值表达式b:
    

  
    (7) 比较运算:比较运算的处理方式和算术运算类似,它也有两个子节点,分别代表子表达式:x 和 y:
    

 
 

     通过上面的方法,就可以把一个表达式转化为一棵语法树。例如,表达式:
 ( let ( x 4 ) ( if true x y ) )
可以转化为如下的语法树:    



    树中的每个节点存储该节点代表的表达式的值,因此求解整个表达式的值就是对语法树由上到下、从左到右进行深度优先搜索的过程,上面的语法树的求解过程如下:
    (i) 首先访问let节点,计算let表达式的值需要首先计算赋值表达式的值,即let节点的第二个子节点。
    (ii) let节点的第二个节点是一个数字,其值可以直接读出。该节点求解完成。回溯到根节点let。
    (iii) 接下来,求解let表达式中的求值表达式,即let节点的第3个子节点。
    (iv) 求解let节点的第三个子节点的值,该节点是if节点,需要先求解它的第1个子节点的值。
    (v) if节点的第一个子节点为布尔值,节点的值可以直接读出,该节点求解完毕。回溯到if节点。
    (vi) 由于第一个节点的结果是true,因此此时需要求解if节点的第二个子节点的值。
    (vii) if节点的第二个节点是变量,此时x已经被绑定为4,因此该节点的值是4,求解完毕,回溯到if节点。
    (viii) 此时if节点可以求解,它的值就是第2个节点的值,if节点求解完毕回溯到let节点。
    (ix) 此时let节点也可以求值了,它的值就是它第三个节点的值,结果是4。整个表达式的值求解完毕。
    因此,利用语法树求解表达式的值的基本过程就是:从根节点采用深度优先搜索的方式对树进行遍历,如果某个节点有子节点则递归求解子节点的值,然后求解本节点的值后返回。这样遍历完成后就可以从树的根节点中找到整个表达式的值。如果在求解过程中发现题目中说明的非法情况,则输出相关信息,求解结束。
    在每一轮递归过程中,在完成子节点的求解后,在求解本节点的值的过程根据语法的定义求解即可。这里需要说明的是let表达式的求解过程,由于求解let节点的第3个子节点的值的过程中会遇到变量,而变量的值则由let节点的第1、2个子节点决定。因此在求解let节点的第3个子节点的值时会用到这些信息。这里可以定义一个“变量表”来存储每一个变量的值,在求解过程中,如果遇到了变量,就查找这个变量表找到对应变量的值即可,如果找不到对应的表项,则说明该变量没有绑定值,求解非法。
    例如:表达式:( let ( x 1 ) ( let ( x 2 ) ( + x 1 ) ) ) 的语法树和变量表如下:



 
    由于内层变量的绑定会覆盖掉外层,因此在查找变量的值时,要从下向上查找,第一个符合的表项就是要找的变量的值。

输入输出格式:
    输入:第一行为一个整数T,表示有T组测试数据;
            接下来的T行,每一行为一个字符串,表示一个Lisp表达式。
    输出:对于每一个表达式,输出一行,显示表达式的值,如果表达式非法,则输出出错信息。

程序代码:

/****************************************************/
/* File        : hiho_week_87.cpp                   */
/* Author      : Zhang Yufei                        */
/* Date        : 2016-03-01                         */
/* Description : HihoCoder ACM program. (submit:g++)*/
/****************************************************/

/*
* Update log:
*		Create by Zhang Yufei in 2016-03-01 ~ 2016-03-02.
*		Submit result: CE->PE->AC.
* End.
*/

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

/*
* Define the closure to record variant in the situation of program
*/
typedef struct node {
int value;
int value_type;
char name[25];
struct node *pre;
} Closure;

/*
* Define the super class of s_expression.
* Parameters:
*		@type: The type of this expression. The value is as follow:
*		+-------+------------------------------------------------+
*		| value | 		type                             |
*              +-------+------------------------------------------------+
*              |   0   |	nonnegtive integer                       |
*              +-------+------------------------------------------------+
*		|   1   |	boolean value: true, false               |
*              +-------+------------------------------------------------+
*		|   2   |  <span style="white-space:pre">	</span>variant                                  |
*		+-------+------------------------------------------------+
*		|   3   |	add: + x y                               |
*		+-------+------------------------------------------------+
*		|   4   |	substract: - x y                         |
*		+-------+------------------------------------------------+
*		|   5   |	multiply: * x y                          |
*		+-------+------------------------------------------------+
*		|   6   |	devide: / x y                            |
*		+-------+------------------------------------------------+
*		|   7   |	if expression: if a b c                  |
*		+-------+------------------------------------------------+
*		|   8   |	let expression: let ( x a ) b            |
*		+-------+------------------------------------------------+
*		|   9   |	greater comparision: > x y               |
*		+-------+------------------------------------------------+
*		|   10  |	equal comparision: = x y                 |
*		+-------+------------------------------------------------+
*		|   11  |	less comparision: < x y                  |
*		+-------+------------------------------------------------+
*		@value: The value of this s_expression.
*		@value_type: The type of value.
*/
typedef struct node1 {
int type;
int value;
int value_type;
} s_expression;

/*
* The sub-classes of s_expression:
*/

// nonnegtive integer
typedef struct node2 {
int type;
int value;
int value_type;
} Integer;

// boolean
typedef struct node3 {
int type;
int value;
int value_type;
} Boolean;

typedef struct node4 {
int type;
int value;
int value_type;
char name[20];
} Variant;

// + x y
typedef struct node5 {
int type;
int value;
int value_type;
s_expression *x, *y;
} Add;

// - x y
typedef struct node6 {
int type;
int value;
int value_type;
s_expression *x, *y;
} Substract;

// * x y
typedef struct node7 {
int type;
int value;
int value_type;
s_expression *x, *y;
} Multiply;

// / x y
typedef struct node8 {
int type;
int value;
int value_type;
s_expression *x, *y;
} Devide;

// if a b c
typedef struct node9 {
int type;
int value;
int value_type;
s_expression *a, *b, *c;
} If;

// let (x a) b
typedef struct node10 {
int type;
int value;
int value_type;
s_expression *x, *a, *b;
} Let;

// < x y
typedef struct node11 {
int type;
int value;
int value_type;
s_expression *x, *y;
} Greater;

// = x y
typedef struct node12 {
int type;
int value;
int value_type;
s_expression *x, *y;
} Equal;

// < x y
typedef struct node13 {
int type;
int value;
int value_type;
s_expression *x, *y;
} Less;

// The input data.
char input[250];
// The length of input.
int length;
// The curren index in the process of interpreting.
int start;

/*
* This function deals with one test case.
* Parameters:
*		None.
* Returns:
*		None.
*/
void function(void);

/*
* This function sets a synax tree using given input s_expression.
* Parameters:
*		None.
* Return:
*		The root node of the synax tree.
*/
s_expression* set_tree(void);

/*
* This function transfers the string into nodes in synax tree
* Parameters:
*		None.
* Returns:
*		The node created by this function.
*/
s_expression* make_node(void);

/*
* This function calculates the value of the input s_expression.
* Parameter:
*		@expression: The root of synax tree generated by input s_expression.
*		@closure: The current closure node of the situation.
* Return:
*		If computing process is correct and the result has been worked out,
*		returns 1, or returns 0.
*/
int calculate(s_expression *expression, Closure *closure);

/*
* The main progarm.
*/
int main(void) {
int T;
scanf("%d", &T);
getchar();
for(int i = 0; i < T; i++) {
function();
}

return 0;
}

/*
* This function deals with one test case.
* Parameters:
*		None.
* Returns:
*		None.
*/
void function(void) {
gets(input);
length = strlen(input);
start = 0;
s_expression *s = set_tree();
if(calculate(s, NULL) == 1) {
if(s->value_type == 0) {
printf("%d\n", s->value);
} else if(s->value_type == 1) {
if(s->value == 1) {
printf("true\n");
} else {
printf("false\n");
}
}
}
}

/*
* This function sets a synax tree using given input s_expression.
* Parameters:
*		None
* Return:
*		The root node of the synax tree.
*/
s_expression* set_tree(void) {
s_expression *s = make_node();
switch (s->type) {
case 0: break;
case 1: break;
case 2: break;
case 3: { Add *add = (Add*)s;
add->x = set_tree();
add->y = set_tree();
break; }
case 4: { Substract *substract = (Substract*)s;
substract->x = set_tree();
substract->y = set_tree();
break; }
case 5: { Multiply *multiply = (Multiply*)s;
multiply->x = set_tree();
multiply->y = set_tree();
break; }
case 6: { Devide *devide = (Devide*)s;
devide->x = set_tree();
devide->y = set_tree();
break; }
case 7:	{ If *iF = (If*)s;
iF->a = set_tree();
iF->b = set_tree();
iF->c = set_tree();
break; }
case 8: { Let *let = (Let*)s;
let->x = set_tree();
let->a = set_tree();
let->b = set_tree();
break; }
case 9: { Greater *greater = (Greater*)s;
greater->x = set_tree();
greater->y = set_tree();
break; }
case 10: { Equal *equal = (Equal*)s;
equal->x = set_tree();
equal->y = set_tree();
break; }
case 11: { Less *less = (Less*)s;
less->x = set_tree();
less->y = set_tree();
break; }
default: break;
}

return s;
}

/*
* This function transfers the string into nodes in synax tree
* Parameters:
*		None
* Returns:
*		The node created by this function.
*/
s_expression* make_node(void) {
s_expression *node;

while(start < length && (isblank(input[start]) ||
input[start] == ')' || input[start] == '('))
start++;

if(isdigit(input[start])) {
Integer *integer = (Integer*) malloc(sizeof(Integer));
int num = 0;
while(isdigit(input[start])) {
num *= 10;
num += input[start] - 48;
start++;
}
integer->type = 0;
integer->value = num;
node = (s_expression*) integer;
} else if(input[start] == '+') {
Add *add = (Add*) malloc(sizeof(Add));
add->type = 3;
node = (s_expression*) add;
start++;
} else if(input[start] == '-') {
Substract *substract = (Substract*) malloc(sizeof(Substract));
substract->type = 4;
node = (s_expression*) substract;
start++;
} else if(input[start] == '*') {
Multiply *multiply = (Multiply*) malloc(sizeof(Multiply));
multiply->type = 5;
node = (s_expression*) multiply;
start++;
} else if(input[start] == '/') {
Devide *devide = (Devide*) malloc(sizeof(Devide));
devide->type = 6;
node = (s_expression*) devide;
start++;
} else if(input[start] == '>') {
Greater *greater = (Greater*) malloc(sizeof(Greater));
greater->type = 9;
node = (s_expression*) greater;
start++;
} else if(input[start] == '=') {
Equal *equal = (Equal*) malloc(sizeof(Equal));
equal->type = 10;
node = (s_expression*) equal;
start++;
} else if(input[start] == '<') {
Less *less = (Less*) malloc(sizeof(Less));
less->type = 11;
node = (s_expression*) less;
start++;
} else if(isalpha(input[start])) {
char ch[15];
int index = 0;
while(isalpha(input[start])) {
ch[index++] = input[start++];
}
ch[index] = '\0';

if(strcmp("if", ch) == 0) {
If *iF = (If*) malloc(sizeof(If));
iF->type = 7;
node = (s_expression*) iF;
} else if(strcmp("let", ch) == 0) {
Let *let = (Let*) malloc(sizeof(Let));
let->type = 8;
node = (s_expression*) let;
} else if(strcmp("true", ch) == 0 || strcmp("false", ch) == 0) {
Boolean *boolean = (Boolean*) malloc(sizeof(Boolean));
boolean->type = 1;
if(strcmp("true", ch) == 0) {
boolean->value = 1;
} else {
boolean->value = 0;
}
node = (s_expression*) boolean;
} else {
Variant *variant = (Variant*) malloc(sizeof(Variant));
variant->type = 2;
strcpy(variant->name, ch);
node = (s_expression*) variant;
}
}

return node;
}

/*
* This function calculates the value of the input s_expression.
* Parameter:
*		@expression: The root of synax tree generated by input s_expression.
*		@closure: The current closure node of the situation.
* Return:
*		If computing process is correct and the result has been worked out,
*		returns 1, or returns 0.
*/
int calculate(s_expression *expression, Closure *closure) {
int type = expression->type;

switch (type) {
case 0: expression->value_type = 0; return 1;         // Integer.
case 1: expression->value_type = 1; return 1;         // Boolean.
case 2: {Closure *c = closure;                         // variant.
Variant *v = (Variant*) expression;
while(c != NULL) {
if(strcmp(v->name, c->name) == 0) {
v->value = c->value;
v->value_type = c->value_type;
return 1;
}
c = c->pre;
}
printf("Unbound Identifier\n");
return 0; }
case 3: { Add *add = (Add*) expression;                 // + x y
if(calculate(add->x, closure) == 0) {
return 0;
}
if(calculate(add->y, closure) == 0) {
return 0;
}
if(add->x->value_type != 0
|| add->y->value_type != 0) {
printf("Type Mismatch\n");
return 0;
}
add->value = add->x->value + add->y->value;
add->value_type = 0;
return 1; }
case 4: { Substract *substract = (Substract*) expression;// - x y
if(calculate(substract->x, closure) == 0) {
return 0;
}
if(calculate(substract->y, closure) == 0) {
return 0;
}
if(substract->x->value_type != 0 || substract->y->value_type != 0) {
printf("Type Mismatch\n");
return 0;
}

substract->value = substract->x->value - substract->y->value;
substract->value_type = 0;
return 1; }
case 5: { Multiply *multiply = (Multiply*) expression;   // * x y
if(calculate(multiply->x, closure) == 0) {
return 0;
}
if(calculate(multiply->y, closure) == 0) {
return 0;
}
if(multiply->x->value_type != 0 || multiply->y->value_type != 0) {
printf("Type Mismatch\n");
return 0;
}

multiply->value = multiply->x->value * multiply->y->value;
multiply->value_type = 0;
return 1; }
case 6: { Devide *devide = (Devide*) expression;         // / x y
if(calculate(devide->x, closure) == 0) {
return 0;
}
if(calculate(devide->y, closure) == 0) {
return 0;
}
if(devide->x->value_type != 0 || devide->y->value_type != 0) {
printf("Type Mismatch\n");
return 0;
}
if(devide->y->value == 0) {
printf("Division By Zero\n");
return 0;
}
devide->value = devide->x->value / devide->y->value;
devide->value_type = 0;
return 1; }
case 7: { If *iF = (If*) expression;                    // if a b c
if(calculate(iF->a, closure) == 0) {
return 0;
}
if(iF->a->value_type != 1) {
printf("Type Mismatch\n");
return 0;
}
if(iF->a->value == 1) {
if(calculate(iF->b, closure) == 0) {
return 0;
}
iF->value = iF->b->value;
iF->value_type = iF->b->value_type;
return 1;
} else {
if(calculate(iF->c, closure) == 0) {
return 0;
}
iF->value = iF->c->value;
iF->value_type = iF->c->value_type;
return 1;
} }
case 8: { Let *let = (Let*) expression;               // let ( x a ) b
if(calculate(let->a, closure) == 0) {
return 0;
}
Closure *new_c = (Closure*) malloc(sizeof(Closure));
new_c->value = let->a->value;
new_c->value_type = let->a->value_type;
strcpy(new_c->name, ((Variant*) (let->x))->name);
new_c->pre = closure;

if(calculate(let->b, new_c) == 0) {
free(new_c);
return 0;
}
free(new_c);
let->value = let->b->value;
let->value_type = let->b->value_type;
return 1; }
case 9: { Greater *greater = (Greater*) expression;   // > x y
if(calculate(greater->x, closure) == 0) {
return 0;
}
if(calculate(greater->y, closure) == 0) {
return 0;
}
if(greater->x->value_type != 0 ||
greater->y->value_type != 0) {
printf("Type Mismatch\n");
return 0;
}
if(greater->x->value > greater->y->value) {
greater->value = 1;
greater->value_type = 1;
return 1;
} else {
greater->value = 0;
greater->value_type = 1;
return 1;
} }
case 10: { Equal *equal = (Equal*) expression;   // = x y
if(calculate(equal->x, closure) == 0) {
return 0;
}
if(calculate(equal->y, closure) == 0) {
return 0;
}
if(equal->x->value_type != 0 ||
equal->y->value_type != 0) {
printf("Type Mismatch\n");
return 0;
}
if(equal->x->value == equal->y->value) {
equal->value = 1;
equal->value_type = 1;
return 1;
} else {
equal->value = 0;
equal->value_type = 1;
return 1;
} }
case 11: { Less *less = (Less*) expression;   // < x y
if(calculate(less->x, closure) == 0) {
return 0;
}
if(calculate(less->y, closure) == 0) {
return 0;
}
if(less->x->value_type != 0 ||
less->y->value_type != 0) {
printf("Type Mismatch\n");
return 0;
}
if(less->x->value < less->y->value) {
less->value = 1;
less->value_type = 1;
return 1;
} else {
less->value = 0;
less->value_type = 1;
return 1;
} }
default: return 0;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  acm 微软笔试题