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

来源:互联网 发布:对角化矩阵的谱分解 编辑:程序博客网 时间:2024/06/06 00:55

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

程序会自动分析输入的表达式,并且列出真值表,最后打印出主析取范式和主合取范式,最多支持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;  }