java实现真值表代码

19 阅读5分钟

1. 改进的 Test 类

java

import java.util.*;

public class Test {
    public static void main(String[] args) {
        System.out.println("真值表生成器");
        System.out.println("支持的运算符: !(非), &(与), |(或), ->(蕴含), <->(双条件)");
        System.out.println("支持的变量: 任意小写字母 (a-z)");
        System.out.println("示例: ((a->b)&(!c))");
        
        Scanner input = new Scanner(System.in);
        System.out.print("请输入命题公式: ");
        String formula = input.nextLine().replace(" ", ""); // 去除空格
        
        // 提取所有变量并按字母顺序排序
        Set<Character> variables = extractVariables(formula);
        List<Character> sortedVariables = new ArrayList<>(variables);
        Collections.sort(sortedVariables);
        
        System.out.println("\n变量: " + sortedVariables);
        System.out.println("真值表:");
        
        // 打印表头
        printHeader(sortedVariables, formula);
        
        // 生成并打印真值表
        TruthTable truthTable = new TruthTable();
        truthTable.generateTruthTable(sortedVariables, formula);
    }
    
    // 提取公式中的所有变量
    private static Set<Character> extractVariables(String formula) {
        Set<Character> variables = new HashSet<>();
        for (char c : formula.toCharArray()) {
            if (Character.isLowerCase(c)) {
                variables.add(c);
            }
        }
        return variables;
    }
    
    // 打印表头
    private static void printHeader(List<Character> variables, String formula) {
        // 打印变量名
        for (char var : variables) {
            System.out.print(var + "\t");
        }
        // 打印公式
        System.out.println(formula);
        
        // 打印分隔线
        for (int i = 0; i < variables.size(); i++) {
            System.out.print("---\t");
        }
        System.out.println("---".repeat(Math.max(1, formula.length() / 2)));
    }
}

2. 改进的 TruthTable 类

java

import java.util.*;

public class TruthTable {
    private Map<Character, Boolean> variableValues;
    
    public void generateTruthTable(List<Character> variables, String formula) {
        variableValues = new HashMap<>();
        boolean[] assignments = new boolean[variables.size()];
        generateAssignments(variables, formula, assignments, 0);
    }
    
    // 递归生成所有可能的真值赋值
    private void generateAssignments(List<Character> variables, String formula, 
                                   boolean[] assignments, int index) {
        if (index == variables.size()) {
            // 为当前赋值创建变量映射
            for (int i = 0; i < variables.size(); i++) {
                variableValues.put(variables.get(i), assignments[i]);
            }
            
            // 打印当前赋值和计算结果
            printAssignment(variables, assignments);
            boolean result = evaluateExpression(formula);
            System.out.println(result ? "1" : "0");
            return;
        }
        
        // 递归生成所有可能的赋值
        assignments[index] = false;
        generateAssignments(variables, formula, assignments, index + 1);
        
        assignments[index] = true;
        generateAssignments(variables, formula, assignments, index + 1);
    }
    
    // 打印当前的真值赋值
    private void printAssignment(List<Character> variables, boolean[] assignments) {
        for (int i = 0; i < variables.size(); i++) {
            System.out.print(assignments[i] ? "1\t" : "0\t");
        }
    }
    
    // 计算表达式的真值
    public boolean evaluateExpression(String expression) {
        // 将表达式转换为后缀表达式(逆波兰表示法)
        List<String> postfix = infixToPostfix(expression);
        return evaluatePostfix(postfix);
    }
    
    // 中缀表达式转后缀表达式
    private List<String> infixToPostfix(String expression) {
        List<String> output = new ArrayList<>();
        Stack<Character> operators = new Stack<>();
        
        for (int i = 0; i < expression.length(); i++) {
            char c = expression.charAt(i);
            
            if (Character.isLowerCase(c)) {
                // 变量
                output.add(String.valueOf(c));
            } else if (c == '!') {
                // 非运算符(单目)
                operators.push(c);
            } else if (isOperator(c)) {
                // 双目运算符
                while (!operators.isEmpty() && precedence(operators.peek()) >= precedence(c)) {
                    output.add(String.valueOf(operators.pop()));
                }
                operators.push(c);
            } else if (c == '(') {
                operators.push(c);
            } else if (c == ')') {
                while (!operators.isEmpty() && operators.peek() != '(') {
                    output.add(String.valueOf(operators.pop()));
                }
                operators.pop(); // 弹出 '('
            }
            // 处理多字符运算符 (->, <->)
            else if (c == '-') {
                // 跳过下一个字符 '>'
                i++;
                operators.push('→');
            } else if (c == '<') {
                // 跳过 "- >"
                i += 2;
                operators.push('↔');
            }
        }
        
        while (!operators.isEmpty()) {
            output.add(String.valueOf(operators.pop()));
        }
        
        return output;
    }
    
    // 计算后缀表达式
    private boolean evaluatePostfix(List<String> postfix) {
        Stack<Boolean> stack = new Stack<>();
        
        for (String token : postfix) {
            if (token.length() == 1 && Character.isLowerCase(token.charAt(0))) {
                // 变量
                stack.push(variableValues.get(token.charAt(0)));
            } else {
                char op = token.charAt(0);
                if (op == '!') {
                    // 非运算
                    boolean operand = stack.pop();
                    stack.push(!operand);
                } else {
                    // 双目运算
                    boolean right = stack.pop();
                    boolean left = stack.pop();
                    stack.push(applyOperator(left, right, op));
                }
            }
        }
        
        return stack.pop();
    }
    
    // 应用运算符
    private boolean applyOperator(boolean left, boolean right, char operator) {
        switch (operator) {
            case '&': // 与
                return left && right;
            case '|': // 或
                return left || right;
            case '→': // 蕴含
                return !left || right; // p→q 等价于 !p | q
            case '↔': // 双条件
                return left == right;
            default:
                throw new IllegalArgumentException("未知运算符: " + operator);
        }
    }
    
    // 判断是否为运算符
    private boolean isOperator(char c) {
        return c == '&' || c == '|' || c == '!' || c == '→' || c == '↔';
    }
    
    // 运算符优先级
    private int precedence(char operator) {
        switch (operator) {
            case '!': return 4; // 非最高
            case '&': return 3; // 与
            case '|': return 2; // 或
            case '→': return 1; // 蕴含
            case '↔': return 0; // 双条件最低
            default: return -1;
        }
    }
}

3. 更高级的版本(支持更多特性)

java

import java.util.*;

public class AdvancedTruthTable {
    private Map<Character, Boolean> variableValues;
    private List<String> calculationSteps;
    
    public void generateDetailedTruthTable(String formula) {
        // 提取变量
        Set<Character> variables = new TreeSet<>();
        for (char c : formula.toCharArray()) {
            if (Character.isLowerCase(c)) variables.add(c);
        }
        List<Character> varList = new ArrayList<>(variables);
        
        System.out.println("命题公式: " + formula);
        System.out.println("变量: " + varList);
        System.out.println();
        
        // 打印详细表头
        printDetailedHeader(varList, formula);
        
        // 生成真值表
        variableValues = new HashMap<>();
        calculationSteps = new ArrayList<>();
        generateDetailedTable(varList, formula, new boolean[varList.size()], 0);
    }
    
    private void printDetailedHeader(List<Character> variables, String formula) {
        // 变量列
        for (char var : variables) {
            System.out.print(var + "\t");
        }
        // 公式列
        System.out.print(formula + "\t");
        // 计算步骤
        System.out.println("计算过程");
        
        // 分隔线
        int totalWidth = variables.size() * 3 + formula.length() + 10;
        System.out.println("-".repeat(totalWidth));
    }
    
    private void generateDetailedTable(List<Character> variables, String formula, 
                                     boolean[] assignments, int index) {
        if (index == variables.size()) {
            // 设置变量值
            for (int i = 0; i < variables.size(); i++) {
                variableValues.put(variables.get(i), assignments[i]);
            }
            
            // 打印赋值
            for (boolean assignment : assignments) {
                System.out.print(assignment ? "1\t" : "0\t");
            }
            
            // 计算并打印结果
            calculationSteps.clear();
            boolean result = evaluateWithSteps(formula);
            System.out.print(result ? "1\t\t" : "0\t\t");
            
            // 打印计算步骤
            System.out.println(String.join(" → ", calculationSteps));
            return;
        }
        
        assignments[index] = false;
        generateDetailedTable(variables, formula, assignments, index + 1);
        
        assignments[index] = true;
        generateDetailedTable(variables, formula, assignments, index + 1);
    }
    
    private boolean evaluateWithSteps(String expression) {
        List<String> postfix = infixToPostfix(expression);
        return evaluatePostfixWithSteps(postfix);
    }
    
    private boolean evaluatePostfixWithSteps(List<String> postfix) {
        Stack<Boolean> stack = new Stack<>();
        Stack<String> stepStack = new Stack<>();
        
        for (String token : postfix) {
            if (token.length() == 1 && Character.isLowerCase(token.charAt(0))) {
                boolean value = variableValues.get(token.charAt(0));
                stack.push(value);
                stepStack.push(token + "=" + (value ? "1" : "0"));
            } else {
                char op = token.charAt(0);
                if (op == '!') {
                    boolean operand = stack.pop();
                    String operandStep = stepStack.pop();
                    boolean result = !operand;
                    stack.push(result);
                    
                    String step = "!" + operandStep + "=" + (result ? "1" : "0");
                    stepStack.push(step);
                    calculationSteps.add(step);
                } else {
                    boolean right = stack.pop();
                    boolean left = stack.pop();
                    String rightStep = stepStack.pop();
                    String leftStep = stepStack.pop();
                    boolean result = applyOperator(left, right, op);
                    stack.push(result);
                    
                    String step = "(" + leftStep + op + rightStep + ")=" + (result ? "1" : "0");
                    stepStack.push(step);
                    calculationSteps.add(step);
                }
            }
        }
        
        return stack.pop();
    }
    
    // 复用之前的辅助方法
    private List<String> infixToPostfix(String expression) {
        List<String> output = new ArrayList<>();
        Stack<Character> operators = new Stack<>();
        
        for (int i = 0; i < expression.length(); i++) {
            char c = expression.charAt(i);
            
            if (Character.isLowerCase(c)) {
                output.add(String.valueOf(c));
            } else if (c == '!') {
                operators.push(c);
            } else if (isOperator(c)) {
                while (!operators.isEmpty() && precedence(operators.peek()) >= precedence(c)) {
                    output.add(String.valueOf(operators.pop()));
                }
                operators.push(c);
            } else if (c == '(') {
                operators.push(c);
            } else if (c == ')') {
                while (!operators.isEmpty() && operators.peek() != '(') {
                    output.add(String.valueOf(operators.pop()));
                }
                operators.pop();
            } else if (c == '-') {
                i++;
                operators.push('→');
            } else if (c == '<') {
                i += 2;
                operators.push('↔');
            }
        }
        
        while (!operators.isEmpty()) {
            output.add(String.valueOf(operators.pop()));
        }
        
        return output;
    }
    
    private boolean applyOperator(boolean left, boolean right, char operator) {
        switch (operator) {
            case '&': return left && right;
            case '|': return left || right;
            case '→': return !left || right;
            case '↔': return left == right;
            default: throw new IllegalArgumentException("未知运算符: " + operator);
        }
    }
    
    private boolean isOperator(char c) {
        return c == '&' || c == '|' || c == '!' || c == '→' || c == '↔';
    }
    
    private int precedence(char operator) {
        switch (operator) {
            case '!': return 4;
            case '&': return 3;
            case '|': return 2;
            case '→': return 1;
            case '↔': return 0;
            default: return -1;
        }
    }
}

4. 使用示例

java

public class TruthTableDemo {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        
        System.out.println("选择模式:");
        System.out.println("1. 基础真值表");
        System.out.println("2. 详细计算过程");
        System.out.print("请输入选择 (1 或 2): ");
        
        int choice = input.nextInt();
        input.nextLine(); // 消耗换行符
        
        System.out.print("请输入命题公式: ");
        String formula = input.nextLine().replace(" ", "");
        
        if (choice == 1) {
            // 基础版本
            Set<Character> variables = new TreeSet<>();
            for (char c : formula.toCharArray()) {
                if (Character.isLowerCase(c)) variables.add(c);
            }
            List<Character> varList = new ArrayList<>(variables);
            
            TruthTable tt = new TruthTable();
            tt.generateTruthTable(varList, formula);
        } else {
            // 详细版本
            AdvancedTruthTable att = new AdvancedTruthTable();
            att.generateDetailedTruthTable(formula);
        }
    }
}

主要改进点

1. 变量处理

  • 自动提取所有小写字母作为变量
  • 支持任意数量的变量(不再限制为a-j)
  • 变量按字母顺序自动排序

2. 运算符支持

  • ! 或 :非
  • & 或 :与
  • | 或 :或
  • -> 或 :蕴含
  • <-> 或 :双条件

3. 算法改进

  • 使用逆波兰表示法(后缀表达式)进行求值
  • 正确处理运算符优先级
  • 支持复杂的嵌套表达式

4. 用户体验

  • 清晰的表头显示
  • 可选的计算过程展示
  • 更好的错误处理

5. 测试示例

text

输入: ((a->b)&(!c))
输出:
a	b	c	((a->b)&(!c))
---	---	---	---------------
0	0	0	1
0	0	1	0
0	1	0	1
0	1	1	0
1	0	0	0
1	0	1	0
1	1	0	1
1	1	1	0

这个改进版本消除了您原代码的限制,现在可以处理任意变量、复杂的嵌套表达式,并且提供了更好的可读性和可扩展性。