[栈的应用] 打印任意命题公示的真值表和主范式(这是转载同学的)

课本是高等教育出版社出版的《离散数学及其应用》。

程序会自动分析输入的表达式,并且列出真值表,最后打印出主析取范式和主合取范式,最多支持256 个变元。

主要用到的算法:中缀表达式转后缀表达式、后缀表达式求值还有一个二进制加法模拟。


下面上2 个图,第一个是表达式开头没有非运算的(课本P85 例3.5.5):


第二个不但表达式开头有非运算,而且非运算之后并不是一个数值,而是一个操作符(课本P83 例3.5.4):

下面是代码,如果CSDN 的编辑器弄乱了就将就着看吧,本来代码的缩进和排版都是整洁的。

file:///main.c

* main.c 
 * use MinGW Developer Studio to compile 
 * by iSpeller (shell_way@foxmail.com) 
 */  
  
#include <stdio.h>   
#include <stdlib.h>   
#include <string.h>   
  
#define _BUF_LEN    (1<<10)   
#define _STACK_LEN  (_BUF_LEN/2)   
#define _PROP_LEN   (1<<7)   
  
#define VOID_NUM    (0) /* 不存在的运算数 */   
typedef char *  string;  
typedef int bool;  
#define true    (1)   
#define false   (0)   
typedef int     data_t;  
/* 防止各种老式编译器来大姨妈 */  
#ifndef _SIZE_T   
typedef unsigned int    size_t;  
#endif   
#ifndef _SSIZE_T   
typedef int ssize_t;  
#endif   
  
/* 范式类型,     析取,    合取 */  
enum paradigm   { EXTRACT, CONJUNCT, };  
/* 优先级大小     等于, 小于,   大于 */  
enum priorities { EG=0, NGE=-1, NLE=1, };  
/* 联结词(包括英文圆括号)优先级,全真 */  
/*     左括号, 非,    合取,  析取, 蕴含,   右括号,  结束符 */  
enum { LEFT=5, NOT=4, AND=3, OR=3, CONT=3, RIGHT=2, END=1, };  
  
/* 4个栈,expr 储存后缀表达式,truth_expr 是expr 的真值解释 
 * ops 储存联结词, truth 做后缀表达式求值栈,truth 最后存放表达式真值  
 */  
struct  stack {  
    data_t data[_STACK_LEN];  
    ssize_t len;  
    size_t len_max;  
}expr, truth_expr, ops, truth;    
string  input_buf = NULL;   /* 存放输入的表达式 */  
struct  prop {    
    char p; /* 变元名 */  
    bool v; /* 真值 */  
};  
struct  table {  
    struct prop data[_PROP_LEN];  
    ssize_t len;  
    size_t len_max;  
} prop_table;   /* 原子命题变元的列表 */  
typedef int truth_item;  
struct truth_table {  
    truth_item data[_STACK_LEN];  
    ssize_t len;  
    size_t len_max;  
} truth_table;  /* 真值表 */  
  
#define push(s,a)   ((s).data[++(s).len] = (a))   
#define pop(s)      ((s).data[(s).len--])   
#define is_empty(s) ((s).len+1)   
#define get_top(s)  ((s).data[(s).len])   
#define init(s,m)   (((s).len = -1) || ((s).len_max = (m)))   
  
#define STRCMP(a,r,b)   (strcmp ((a), (b)) r 0)   
  
/* 判断字符是否是原子命题变元 
 */  
bool  
is_op (char c) {  
    switch (c) {  
    case '|':   return OR;      break;  
    case '&':   return AND;     break;  
    case '!':   return NOT;     break;  
    case '>':    return CONT;    break;  
    case '(':   return LEFT;    break;  
    case ')':   return RIGHT;   break;  
    case '#':   return END;     break;    
    default :   return false;  
    }  
}  
  
/* 判断运算符的优先级 
 */  
enum priorities  
get_priority (char op1, char op2) {  
    if (is_op (op1) == is_op (op2))  
        return EG;  
    else if (is_op (op1) < is_op (op2))  
        return NGE;  
    else  
        return NLE;  
}  
  
/* 进行数据运算 
 */  
data_t  
do_op (char op, bool num1, bool num2) {  
    bool truth = false;  
      
    if('!' == op)   
        return num1 ? false : true;  
    switch (op) {  
    case '|':   truth = (num2 || num1); break;  
    case '&':   truth = (num2 && num1); break;  
    case '>':    truth = (num2 && !num1) ? false : true; break;  
    default:    fprintf (stderr, "Boy, WHAT Did U Have Done!!??\n");  
                exit (0);  
    }  
    return truth;  
}  
  
/* 判断识别的命题变元是否已经存在 
 */  
bool  
prop_find (struct prop item) {  
    ssize_t count = 0;  
      
    for (count=0; count<prop_table.len+1; ++count)  
        if (item.p == prop_table.data[count].p)  
            return true;  
    return false;  
}  
  
/* 判断变元真值是否设置完毕 
 * 如果真值全真返回真 
 */  
bool  
set_truth_end (void) {  
    ssize_t count;  
      
    for (count=0; count<prop_table.len+1; ++count)  
        if (!prop_table.data[count].v)  
            return false;  
      
    return true;  
}  
   
/* 输出“你好” 
 */  
void  
start (void) {  
    printf ("输入诸如\"P|(Q&R)>!P\" 的表达式,程序将会列出真值表并求出主范式。\n\n");  
    printf ("其中:\"|\"表示析取;\"&\"表示合取;\"!\"表示非;\">\"表示蕴含。支持英文圆括号。\n");  
    printf ("字符串处理不是算法的核心,所以不会处理非法输入\n");  
    printf ("\t----因此当你输入了非法的表达式,你也会得到一个非法的结果 :D\n");  
    printf ("exit 指令退出。\n\n");  
}  
  
/* 要求用户输入表达式和原子命题变元的真值 
 */  
void  
get_input () {  
    char *loc = input_buf;  
    size_t size = 0;  
    struct prop item;  
      
    /* 清栈 */  
    init (expr, _STACK_LEN);   
    init (ops, _STACK_LEN);  
    init (truth_expr, _STACK_LEN);  
    init (truth, _STACK_LEN);  
    init (truth_table, _STACK_LEN);  
    init (prop_table, _PROP_LEN);  
      
    if (!(input_buf = (char *)malloc (_BUF_LEN))) {  
        perror ("malloc ()");  
        exit (1);  
    }  
              
    /* 获取表达式 */  
    do {  
        printf (" # ");  
        if (!fgets (input_buf, _BUF_LEN-1, stdin)) {  
            perror ("fgets ()");  
            exit (1);  
        }  
        input_buf[strlen (input_buf)-1] = '#';  /* 结束符号 */  
      
        if (STRCMP ("exit#", ==, input_buf)) {  
            printf ("再见 :D\n");  
            exit (0);  
        }  
    } while (STRCMP ("#", ==, input_buf));  
      
    /* 识别原子命题变元和联结词并压入变元列表 */  
    size = strlen (input_buf);  
    for (loc = input_buf; loc-input_buf < size; ++loc) {  
        if (' ' != *loc)   
            if (!is_op (*loc)) {  
                item.p = *loc;  
                if (!prop_find (item))  
                    push (prop_table, item);    /* 现在并不赋真值 */  
            }   
    }  
}  
  
/* input_buf 中的表达式转换为后缀表达式 
 */  
void  
make_postfix_expr () {  
    data_t item;  
    ssize_t count;  
    enum priorities level;  
      
    push (ops, '#');    /* 栈底元素,结束符号,优先级最小 */  
    for (count=0; count<strlen (input_buf); ++count) {  
        item = input_buf[count];  
          
        if (' ' == item)  
            continue;  
          
        if (!is_op (item))  /* 是操作数则压入表达式栈 */  
            push (expr, item);  
        else if (')' == item || '#' == item) {  /* 去除成对的括号和结束标记'#' */  
            while ('#' != (item = pop (ops)))  
                push (expr, item);  
            pop (ops);  
        } else {  
            level = get_priority (item, get_top (ops));  
              
            /* 通过压入一个不存在的操作数,把单目运算符'!'  
             * 当作双目运算符来处理 
             */  
            if ('!' == item)      
                push (expr, VOID_NUM);  
              
            if (NLE == level) {     /* 如果后进运算符高于栈顶元素 */  
                push (ops, item);       /* 压入运算符栈 */      
                if ('(' == item)        /* 如果压入了一个左括号 */  
                    push (ops, '#');        /* 压入运算符栈一个结束标记来保持正确的优先级 */  
            } else {                /* 否则 */  
                push (expr, pop (ops)); /* 栈顶元素压入表达式栈 */  
                push (ops, item);       /* 后进运算符压入运算符栈 */  
            }  
        }  
    }  
    free (input_buf);  
}  
  
/* 设置变元的初始真值,全假 
 */  
void  
init_props_truth (void) {  
    ssize_t count = 0;  
      
    for (count=0; count<prop_table.len+1; ++count)   
        prop_table.data[count].v = false;  
      
    for (count=0; count<prop_table.len+1; ++count)  
        printf ("%d ", prop_table.data[count].v);  
          
    /* 立刻计算一次真值,因为其后的计算不包含全假的情况 */  
    void find_truth (void);  
    find_truth ();  
}  
  
/* 设置变元的真值,把所有变元当做一个二进制数 
 * 用二进制加法模拟真值,每次调用函数都会给二进制数加一 
 */  
void  
set_props_truth (void) {  
    bool carry = false; /* 进位标志 */  
    ssize_t count, count2;  
      
    for (count=0, carry=true; carry && (count<prop_table.len+1); ++count) {  
            if (prop_table.data[count].v) {  
                prop_table.data[count].v = (carry ? 0 : 1);  
                if (prop_table.len>0)  
                    /* 同时要处理前面的位 */  
                    for (count2=1; count2<count+1; ++count2)  
                        prop_table.data[count-count2].v = false;  
                carry = (prop_table.data[count].v ? false : true);  
            } else {      
                prop_table.data[count].v = (carry ? 1 : 0);  
                carry = false;  
            }  
    }  
      
    for (count=0; count<prop_table.len+1; ++count)  
            printf ("%d ", prop_table.data[count].v);  
    void find_truth (void);  
    find_truth ();  
}  
  
/* 调用函数之时默认prop_table 已经设置了一组有效的真值 
 * 函数计算在这组真值下整个后缀表达式的真值 
 */  
void  
find_truth (void) {  
    truth_item item;  
    ssize_t count, count2;  
    data_t data, num1, num2, ans;  
      
    /* 首先把truth_expr 中的变元全部换成真值 */  
    truth_expr = expr;  
    for (count=0; count<truth_expr.len+1; ++count) {  
        data =  truth_expr.data[count];  
          
        if (!is_op (data)) {  
            for (count2=0; count2<prop_table.len+1; ++count2)  
                if (data == prop_table.data[count2].p) {  
                    truth_expr.data[count] = prop_table.data[count2].v;  
                    break;  
                }  
        }  
    }  
      
    /* 后缀表达式求值 */  
    for (count=0; count<truth_expr.len+1; ++count) {  
        data =  truth_expr.data[count];  
          
        if (!is_op (data))      /* 非运算符 */  
            push (truth, data);  
        else {                  /* 是运算符 */  
            num1 = pop (truth);  
            num2 = pop (truth);  
            ans = do_op (data, num1, num2);  
            push (truth, ans);  
        }  
    }     
      
    /* 储存真值 */  
    item = pop (truth);  
    push (truth_table, item);  
      
    /* 顺便打印真值 */  
    printf ("\t%d\n", truth_table.data[truth_table.len]);  
}  
  
/* 打印主范式 
 */  
void      
print_main_paradigm (enum paradigm type) {  
    ssize_t count;  
    bool has_find;  
      
    if ((EXTRACT!=type) && (CONJUNCT!=type))  
        exit (0);  
      
    printf ("主%s范式为 : ", (EXTRACT==type) ? "析取" : "合取");  
    for (count=0, has_find=false; count<truth_table.len+1; ++count) {  
        if ((EXTRACT==type)   
            ? truth_table.data[count]  
            : !truth_table.data[count]) {  
            has_find = true;  
            printf ("%c%d %s ", (EXTRACT==type) ? 'm' : 'M',   
                                count,  
                                (EXTRACT==type) ? "∨" : "∧");  
        }  
    }  
    if (has_find)  
        printf ("\b\b  \n");  
    else   
        printf ("为空");  
}  
  
/* MAIN  
 */  
int  
main (int argc, char *argv[]) {  
    ssize_t count;  
      
    start ();  
      
    while (true) {  
        get_input ();  
        make_postfix_expr ();  
          
        for (count=0; count<prop_table.len+1; ++count) {  
            printf ("%c ", prop_table.data[count].p);  
        }  
        printf ("\t真值\n\n");  
          
        init_props_truth ();  
          
        while (!set_truth_end ())  
            set_props_truth ();  
          
        print_main_paradigm (EXTRACT);  /* 主析取范式 */  
        print_main_paradigm (CONJUNCT); /* 主合取范式 */  
    }  
      
    return 0;  
}  


 


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值