回 帖 发 新 帖 刷新版面

主题:求输入逻辑表达式然后得出真值表的算法思路,程序很难写求帮助

要求:输入一个逻辑表达式(如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个回复)

沙发

楼主会不会太冒进了。
前两天还在问栈是怎么回事,现在就开始做这样的题目?
这个题虽然难度不能算高,但是涵盖了很多方面。数据结构,算法,编译原理,这些都必须有一定的了解,否则难以把这个题目做好。
昨晚两三点钟的时候我看到这个题目,开始编程。因为一些知识太久不用,忘了,然后翻书,搞了很久,到现在总算做出来。累。光想着写程序,调试,睡觉都错过了。最终程序大约400行代码(含注释),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

楼主给出的真值表第四行是错误的,只要C为1,A&B|C = (A&B)|C一定就为1。

3 楼

不是我想要冒进啊,但老师布置的实验就是这么让我纠结[em10]
c语言我基本学的差不多了,现在在学c++,但栈的问题,以前一直没用过,所以不是很明白。

至于那个真值表,搞错了,绝对是个意外
谢谢你啊

4 楼

[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 楼

[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 楼

[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 楼

[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 楼

[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 楼

[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 楼

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
请按任意键继续. . .

我来回复

您尚未登录,请登录后再回复。点此登录或注册