主题:求输入逻辑表达式然后得出真值表的算法思路,程序很难写求帮助
ccmike98
[专家分:80] 发布于 2010-10-23 20:58:00
要求:输入一个逻辑表达式(如A&B|C)然后得出真值表
A B C A&B|C
0 0 0 0
0 0 1 1
0 1 0 0
0 1 1 0
1 0 0 0
1 0 1 1
1 1 0 1
1 1 1 1
很难写的程序希望大家给点思路,
不需要程序,只要把思路说一下就行了
另外,里面有一个运算符优先级的函数不知道怎么写
运算符有 +(双条件)、-(条件)、|、&、!、((左括号)、)(右括号)
+ - | & ! ( )
+ > < < < < < >
- > > < < < < >
| > > > < < < >
& > > > > < < >
! > > > > > < >
( < < < < < < =
) > > > > > E > E表示错误
这是运算符优先级的比较表 比法:先看竖列再在第一行找(例:+与&比较 +<& 即&优先级高)
我记得老师是用一个2维数组写的这个函数。
求那位大神来帮帮我
[em8]
回复列表 (共12个回复)
沙发
eastcowboy [专家分:25370] 发布于 2010-10-24 08:06:00
楼主会不会太冒进了。
前两天还在问栈是怎么回事,现在就开始做这样的题目?
这个题虽然难度不能算高,但是涵盖了很多方面。数据结构,算法,编译原理,这些都必须有一定的了解,否则难以把这个题目做好。
昨晚两三点钟的时候我看到这个题目,开始编程。因为一些知识太久不用,忘了,然后翻书,搞了很久,到现在总算做出来。累。光想着写程序,调试,睡觉都错过了。最终程序大约400行代码(含注释),C语言。
其实无所谓“思路”。既然给出了优先级列表,很明显是希望用算符优先分析法,分析出用户所输入的逻辑表达式的结构。至于真值表,则比较简单,穷举则可。
难点就是算符优先分析法。这个概念来自编译原理,不过在这里也仅仅是一个简单的应用。如果翻书的话,就发现这个分析法主要就是用了一个栈。在不同的条件下,进行出栈、入栈操作,在这个过程中就可以把逻辑表达式的结构分析出来。最终分析得出的是一个树状结构(编译原理中,称之为语法树)。
然后,看看总共用了多少个变量,对这些变量的值进行穷举,就可以输出真值表了。
总之,这个题目其实就是几门大学课程的糅合。没有什么特别难的地方,但是基本功不够扎实的话,那就有够头疼了。
板凳
eastcowboy [专家分:25370] 发布于 2010-10-24 08:09:00
我的输出结果:
A&B|C
A B C A&B|C
0 0 0 0
0 0 1 1
0 1 0 0
0 1 1 1
1 0 0 0
1 0 1 1
1 1 0 1
1 1 1 1
楼主给出的真值表第四行是错误的,只要C为1,A&B|C = (A&B)|C一定就为1。
3 楼
ccmike98 [专家分:80] 发布于 2010-10-24 11:24:00
不是我想要冒进啊,但老师布置的实验就是这么让我纠结[em10]
c语言我基本学的差不多了,现在在学c++,但栈的问题,以前一直没用过,所以不是很明白。
至于那个真值表,搞错了,绝对是个意外
谢谢你啊
4 楼
eastcowboy [专家分:25370] 发布于 2010-10-25 23:15:00
[code=c]/*
程序目的:计算逻辑表达式的真值表
例如:对于逻辑表达式A&B|C,得到以下输出
A B C A&B|C
0 0 0 0
0 0 1 1
0 1 0 0
0 1 1 1
1 0 0 0
1 0 1 1
1 1 0 1
1 1 1 1
逻辑表达式支持:常量(只有0和1两种常量)、变量(用一个大写字母表示,因此最多26个变量)、“与”运算、“或”运算、“非”运算
用算符优先文法来做语法解析。优先级比较表如下:
| & ! ( ) #
| > < < < > <
& > > < < > <
! > > > < > <
( < < < < = <
) > > > E > <
# > > > > > =
算符优先文法解析方式:
1、定义优先级比较表。除了真正需要使用的运算符,还需要一个特殊的符号,记为“#”,表示输入开始和输入结束。(这样一来可以简化代码)
2、书上只使用了一个栈,但这里使用了两个栈。把操作数和操作符区分开。只是为了便于编写代码,没有别的目的。
3、若当前优先级小于栈顶优先级,则规约;若大于,则入栈。
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
// 定义栈的最大容量
#define MAX_STACK_SIZE 50
// 逻辑表达式中,最多可以拥有的变量个数(变量用一个大写字母表示,所以最多26)
#define MAX_VARIANT_NUM 26
// 优先级关系的类型
typedef enum tag_PRECEDE_TYPE
{
PRECEDE_EQUAL,
PRECEDE_GREATER,
PRECEDE_LESS,
PRECEDE_ERROR,
} PRECEDE_TYPE;
// 优先级表
const PRECEDE_TYPE precede_table[6][6] =
{
PRECEDE_GREATER, PRECEDE_LESS, PRECEDE_LESS, PRECEDE_LESS, PRECEDE_GREATER, PRECEDE_GREATER,
PRECEDE_GREATER, PRECEDE_GREATER, PRECEDE_LESS, PRECEDE_LESS, PRECEDE_GREATER, PRECEDE_GREATER,
PRECEDE_GREATER, PRECEDE_GREATER, PRECEDE_GREATER, PRECEDE_LESS, PRECEDE_GREATER, PRECEDE_GREATER,
PRECEDE_LESS, PRECEDE_LESS, PRECEDE_LESS, PRECEDE_LESS, PRECEDE_EQUAL, PRECEDE_GREATER,
PRECEDE_GREATER, PRECEDE_GREATER, PRECEDE_GREATER, PRECEDE_ERROR, PRECEDE_GREATER, PRECEDE_GREATER,
PRECEDE_LESS, PRECEDE_LESS, PRECEDE_LESS, PRECEDE_LESS, PRECEDE_LESS, PRECEDE_EQUAL,
};
// 语法树节点的类型
typedef enum tag_GRAMMAR_NOTE_TYPE
{
GRAMMAR_NODE_TYPE_CONSTANT, // 常量
GRAMMAR_NODE_TYPE_VARIANT, // 变量
GRAMMAR_NODE_TYPE_OP_AND, // “与”运算
GRAMMAR_NODE_TYPE_OP_OR, // “或”运算
GRAMMAR_NODE_TYPE_OP_NOT, // “非”运算
} GRAMMAR_NODE_TYPE;
// 语法树节点
typedef struct tag_GRAMMAR_NODE
{
GRAMMAR_NODE_TYPE type; // 节点类型
int value; // 如果节点类型是常量,则这里记录常量的值;如果节点类型是变量,则这里记录是第几个变量(0到25,分别表示A到Z)
struct tag_GRAMMAR_NODE* op1; // 第一个操作数。如果节点类型是“与”运算、“或”运算、“非”运算,则这里记录了操作所需的数
struct tag_GRAMMAR_NODE* op2; // 第二个操作数。如果节点类型是“与”运算、“或”运算,则这里记录了操作所需的数
} GRAMMAR_NODE;
// 判断优先级的类型
PRECEDE_TYPE JudgePrecede(char op1, char op2)
{
const char* op_list = "|&!()#";
const char* p1 = strchr(op_list, op1);
const char* p2 = strchr(op_list, op2);
if (p1 == NULL || p2 == NULL) {
return PRECEDE_ERROR;
}
return precede_table[p1 - op_list][p2 - op_list];
}
// 销毁语法树
void DestroyGrammarNode(GRAMMAR_NODE* node)
{
if (node == NULL) {
return;
}
DestroyGrammarNode(node->op1);
DestroyGrammarNode(node->op2);
free(node);
}
// 创建一个空的节点
GRAMMAR_NODE* NewGrammarNode(GRAMMAR_NODE_TYPE type)
{
GRAMMAR_NODE* node = (GRAMMAR_NODE*)malloc(sizeof(GRAMMAR_NODE));
if (node == NULL) {
return NULL;
}
node->type = type;
node->value = -1;
node->op1 = NULL;
node->op2 = NULL;
return node;
}[/code]
5 楼
eastcowboy [专家分:25370] 发布于 2010-10-25 23:17:00
[code=c]// 创建语法树
GRAMMAR_NODE* ParseGrammar(const char* input)
{
// val_stack: 操作数栈,op_stack: 操作符栈
GRAMMAR_NODE* val_stack[MAX_STACK_SIZE];
int val_stack_size = 0;
char op_stack[MAX_STACK_SIZE];
int op_stack_size = 0;
if (input == NULL) {
goto error;
}
op_stack[op_stack_size] = '#';
++op_stack_size;
for (; ; ++input) {
char ch = *input;
if (ch == '0' || ch == '1') {
GRAMMAR_NODE* node = NewGrammarNode(GRAMMAR_NODE_TYPE_CONSTANT);
if (node == NULL) {
goto error;
}
node->value = ch - '0';
val_stack[val_stack_size] = node;
++val_stack_size;
} else if (ch >= 'A' && ch <= 'Z') {
GRAMMAR_NODE* node = NewGrammarNode(GRAMMAR_NODE_TYPE_VARIANT);
if (node == NULL) {
goto error;
}
node->value = ch - 'A';
val_stack[val_stack_size] = node;
++val_stack_size;
} else if (ch == '&' || ch == '|' || ch == '!' || ch == '(' || ch == ')' || ch == '\0') {
int flag = 1;
if (ch == '\0') {
ch = '#';
}
while (flag != 0 && op_stack_size > 0) {
switch (JudgePrecede(op_stack[op_stack_size - 1], ch)) {
case PRECEDE_GREATER:
{
switch (op_stack[op_stack_size - 1]) {
case '&':
{
GRAMMAR_NODE* node = NULL;
if (val_stack_size < 2) {
goto error;
}
node = NewGrammarNode(GRAMMAR_NODE_TYPE_OP_AND);
if (node == NULL) {
goto error;
}
[/code]
6 楼
eastcowboy [专家分:25370] 发布于 2010-10-25 23:20:00
[code=c]
node->op1 = val_stack[val_stack_size - 2];
node->op2 = val_stack[val_stack_size - 1];
val_stack_size -= 2;
val_stack[val_stack_size] = node;
++val_stack_size;
--op_stack_size;
}
break;
case '|':
{
GRAMMAR_NODE* node = NULL;
if (val_stack_size < 2) {
goto error;
}
node = NewGrammarNode(GRAMMAR_NODE_TYPE_OP_OR);
if (node == NULL) {
goto error;
}
node->op1 = val_stack[val_stack_size - 2];
node->op2 = val_stack[val_stack_size - 1];
val_stack_size -= 2;
val_stack[val_stack_size] = node;
++val_stack_size;
--op_stack_size;
}
break;[/code]
7 楼
eastcowboy [专家分:25370] 发布于 2010-10-25 23:20:00
[code=c] case '!':
{
GRAMMAR_NODE* node = NULL;
if (val_stack_size < 1) {
goto error;
}
node = NewGrammarNode(GRAMMAR_NODE_TYPE_OP_NOT);
if (node == NULL) {
goto error;
}
node->op1 = val_stack[val_stack_size - 1];
val_stack_size -= 1;
val_stack[val_stack_size] = node;
++val_stack_size;
--op_stack_size;
}
break;
default:
goto error;
}
}
break;
case PRECEDE_LESS:
flag = 0;
break;
case PRECEDE_EQUAL:
if (ch == '#' && op_stack[op_stack_size - 1] == '#') {
--op_stack_size;
}
if (ch == ')' && op_stack[op_stack_size - 1] == '(') {
--op_stack_size;
}
break;
case PRECEDE_ERROR:
default:
goto error;
}
}
if (ch == '#') {
break;
} else if (ch == ')') {
} else {
op_stack[op_stack_size] = ch;
++op_stack_size;
}
} else if (ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t') {
} else {
goto error;
}
}
if (op_stack_size == 0 && val_stack_size == 1) {
return val_stack[0];
}
error:
while (val_stack_size > 0) {
--val_stack_size;
DestroyGrammarNode(val_stack[val_stack_size]);
}
return NULL;
}[/code]
8 楼
eastcowboy [专家分:25370] 发布于 2010-10-25 23:21:00
[code=c]// 根据语法树,逻辑表达式使用了哪些变量
void TraverseGrammarNode(GRAMMAR_NODE* node, int used[MAX_VARIANT_NUM])
{
if (node == NULL) {
return;
}
switch (node->type) {
case GRAMMAR_NODE_TYPE_VARIANT:
used[node->value] = 1;
break;
case GRAMMAR_NODE_TYPE_OP_AND:
case GRAMMAR_NODE_TYPE_OP_OR:
TraverseGrammarNode(node->op1, used);
TraverseGrammarNode(node->op2, used);
break;
case GRAMMAR_NODE_TYPE_OP_NOT:
TraverseGrammarNode(node->op1, used);
break;
case GRAMMAR_NODE_TYPE_CONSTANT:
default:
break;
}
}
// 根据目前变量的值,计算逻辑表达式的值
int Calculate(GRAMMAR_NODE* node, const int variables[MAX_VARIANT_NUM])
{
if (node == NULL) {
assert(0);
return 0;
}
switch (node->type) {
case GRAMMAR_NODE_TYPE_CONSTANT:
return node->value;
case GRAMMAR_NODE_TYPE_VARIANT:
return variables[node->value];
case GRAMMAR_NODE_TYPE_OP_AND:
return Calculate(node->op1, variables) && Calculate(node->op2, variables);
case GRAMMAR_NODE_TYPE_OP_OR:
return Calculate(node->op1, variables) || Calculate(node->op2, variables);
case GRAMMAR_NODE_TYPE_OP_NOT:
return !Calculate(node->op1, variables);
default:
assert(0);
return 0;
}
}[/code]
9 楼
eastcowboy [专家分:25370] 发布于 2010-10-25 23:22:00
[code=c]void PrintTable_impl(GRAMMAR_NODE* node, int position, const int variable_used[MAX_VARIANT_NUM], int variable_values[MAX_VARIANT_NUM])
{
if (position == MAX_VARIANT_NUM) {
int i;
for (i = 0; i < MAX_VARIANT_NUM; ++i) {
if (variable_used[i]) {
printf(" %d", variable_values[i]);
}
}
printf(" %d\n", Calculate(node, variable_values));
return;
}
if (variable_used[position]) {
variable_values[position] = 0;
PrintTable_impl(node, position + 1, variable_used, variable_values);
variable_values[position] = 1;
PrintTable_impl(node, position + 1, variable_used, variable_values);
} else {
PrintTable_impl(node, position + 1, variable_used, variable_values);
}
}
// 打印逻辑表达式的真值表
void PrintTable(GRAMMAR_NODE* node, const char* expr)
{
int variable_used[MAX_VARIANT_NUM] = {0};
int variable_values[MAX_VARIANT_NUM];
int i;
if (node == NULL) {
return;
}
TraverseGrammarNode(node, variable_used);
for (i = 0; i < MAX_VARIANT_NUM; ++i) {
if (variable_used[i]) {
printf(" %c", 'A' + i);
}
}
printf(" %s\n", expr);
PrintTable_impl(node, 0, variable_used, variable_values);
}
int main() {
char input[200];
size_t len = 0;
GRAMMAR_NODE* node = NULL;
for (;;) {
if (!fgets(input, sizeof(input), stdin)) {
break;
}
len = strlen(input);
if (len == 0) {
continue;
}
// 去掉末尾的'\n'
input[len - 1] = '\0';
--len;
if (len == 0) {
continue;
}
node = ParseGrammar(input);
if (node == NULL) {
printf("%s is not a valid expression\n", input);
continue;
}
printf("表达式“%s”的真值表:\n", input);
PrintTable(node, input);
DestroyGrammarNode(node);
}
return 0;
}[/code]
10 楼
eastcowboy [专家分:25370] 发布于 2010-10-25 23:25:00
0
表达式“0”的真值表:
0
0
1
表达式“1”的真值表:
1
1
A
表达式“A”的真值表:
A A
0 0
1 1
!A
表达式“!A”的真值表:
A !A
0 1
1 0
A&A
表达式“A&A”的真值表:
A A&A
0 0
1 1
A|A
表达式“A|A”的真值表:
A A|A
0 0
1 1
!A
表达式“!A”的真值表:
A !A
0 1
1 0
A&B
表达式“A&B”的真值表:
A B A&B
0 0 0
0 1 0
1 0 0
1 1 1
A|B
表达式“A|B”的真值表:
A B A|B
0 0 0
0 1 1
1 0 1
1 1 1
A&!B
表达式“A&!B”的真值表:
A B A&!B
0 0 0
0 1 0
1 0 1
1 1 0
!A&B
表达式“!A&B”的真值表:
A B !A&B
0 0 0
0 1 1
1 0 0
1 1 0
(A|B)&(C|D)
表达式“(A|B)&(C|D)”的真值表:
A B C D (A|B)&(C|D)
0 0 0 0 0
0 0 0 1 0
0 0 1 0 0
0 0 1 1 0
0 1 0 0 0
0 1 0 1 1
0 1 1 0 1
0 1 1 1 1
1 0 0 0 0
1 0 0 1 1
1 0 1 0 1
1 0 1 1 1
1 1 0 0 0
1 1 0 1 1
1 1 1 0 1
1 1 1 1 1
^Z
请按任意键继续. . .
我来回复