public class Main extends JFrame{
private JTextArea jTextArea=new JTextArea();
private JButton jButton=new JButton("选择翻译的文件");
private JPanel jPanel=new JPanel();
public static void main(String[] args) {
new Main();
}
public Main(){
setLayout(new BorderLayout());
jPanel.add(jButton);
add(jPanel,BorderLayout.NORTH);
add(new JScrollPane(jTextArea));
setSize(500,400);
setVisible(true);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jButton.addActionListener(new ActionListener() { //点击按钮,把文件内容翻译为四元式
@Override
public void actionPerformed(ActionEvent e) {
try{
String stringFromFile=getStringFromFile(); //从文件获取算术表达式字符串
String standerdString=toStanderd(stringFromFile); //把字符串转化为合适的格式,比如:23*(78-2)变为23 * ( 78 -2 )这样的形式
String getString_epilogue = getepilogue(standerdString); //中序算术表达式转为后序,比如a*(b-c)转为bc-a*
String getSiYuanShi_string=getSiYuanShi(getString_epilogue);
jTextArea.append(getSiYuanShi_string);
}catch (Exception ex){
}
}
});
}
public String getStringFromFile() throws Exception { //从文件第一行获取算术表达式字符串
JFileChooser fileChooser = new JFileChooser();
fileChooser.showOpenDialog(null);
File file = fileChooser.getSelectedFile(); //选择文件
Scanner read = new Scanner(file);
String str = read.next(); //读取文件第一行
return str;
}
/*这是第一次想到的方法,逻辑上比较绕,感觉不太好理,就写了第二种方法*/
/*public String toStanderd(String string){ //把字符串转化为合适的格式,比如:23*(78-2)变为23 * ( 78 -2 )这样的形式
String standerdString="";
int position=0;
for(int i=0;i<string.length();i++){
if(string.charAt(i)=='*'||string.charAt(i)=='-'||string.charAt(i)=='+'||string.charAt(i)=='/'||string.charAt(i)=='('||string.charAt(i)==')'){
standerdString+=string.substring(position,i)+" "+string.charAt(i)+" ";
position=i+1;
}
if(i==string.length()-1) { //防止字符串最后一个下标不是运算符而加不进去
if (string.charAt(string.length() - 1) != '+' && string.charAt(string.length() - 1) != '-' && string.charAt(string.length() - 1) != '*' && string.charAt(string.length() - 1) != '/' && string.charAt(string.length() - 1) != '(' && string.charAt(string.length() - 1) != ')') {
standerdString += string.charAt(string.length() - 1);
}
}
}
//到这里为止,两个相邻操作符会产生两个空格,再一次标准化处理
String[] str=standerdString.split(" "); //这里是两个空格
standerdString=""; //将之前的字符串清空
for(int i=0;i<str.length;i++){
standerdString+=str[i]+" ";
}
System.out.println(standerdString);
return standerdString;
}*/
/*这种方法比上面注释掉的方法更容易理解*/
/*扫描字符串
* 扫描到操作数,直接加入另一个符号串
* 扫描到符号,将" "+符号+" "加入另一个符号串
* */
public String toStanderd(String string){ //把字符串转化为合适的格式,比如:23*(78-2)变为23 * ( 78 -2 )这样的形式
String standerdString="";
for(int i=0;i<string.length();i++){
if(string.charAt(i)=='-'||string.charAt(i)=='+'||string.charAt(i)=='/'||string.charAt(i)=='*'||string.charAt(i)=='('||string.charAt(i)==')'){
standerdString+=" "+string.charAt(i)+" ";
}else {
standerdString+=string.charAt(i);
}
}
System.out.println(standerdString);
//如果表达式里面有两个符号相连,比如:减号后面是括号,则会之间会产生两个空格,下面代码则把两个空格变为一个空格
String[] str=standerdString.split(" "); //这里是两个空格
standerdString=""; //将之前的字符串清空
for(int i=0;i<str.length;i++){
standerdString+=str[i]+" ";
}
System.out.println(standerdString);
return standerdString;
}
/*扫描到操作数,直接压入操作数栈; - - - -(1)
* 扫描到符号,压入符号栈,压入符号栈的时候,首先判断扫描到的符号,再考虑符号栈栈顶元素;
* 如果符号栈栈空,直接压入; - - - -(2)
* 如果扫描到的符号是"(",直接压入; - - - -(3)
* 如果栈顶元素是"(",直接压入; - - - -(4)
* 如果扫描到")",不压入栈,将最接近符号栈栈顶的"("往栈顶方向走的符号全部压出,再压入操作数栈,再把"("压出; - - - -(5)
* "*"和"/"的优先级都比"-"和"+"的优先级高;
* 扫描到的符号比符号栈栈顶的优先级高,则直接压入,否则先将栈顶元素压出,接着压入操作数栈,再将扫描到的符号压入符号栈 - - - -(6)
* 若中序符号串扫描完成,将符号栈的符号依次压出,压入操作数栈 - - - -(7)
* */
public String getepilogue(String string){ //中序算术表达式转为后序,比如a*(b-c)转为bc-a*
String[] string_array=string.split(" "); //扫描字符串数组,用两个栈来处理,扫描到操作数压入操作数栈,扫描到符号,压入符号栈
Stack<String> stack_operand=new Stack<>(); //操作数栈
Stack<String> stack_symbol=new Stack<>(); //符号栈
for(int i=0;i<string_array.length;i++){
if(string_array[i].equals("+")||string_array[i].equals("-")||string_array[i].equals("*")||string_array[i].equals("/")||string_array[i].equals("(")||string_array[i].equals(")")){
if(stack_symbol.isEmpty()){ //(2)
stack_symbol.push(string_array[i]);
}
else if(string_array[i].equals("(")){ //(3)
stack_symbol.push(string_array[i]);
}
else if(stack_symbol.peek().equals("(")){
stack_symbol.push(string_array[i]); //(4)
}
else if(string_array[i].equals(")")){ //(5)
while(true){
String symbol=stack_symbol.pop();
if(symbol.equals("("))
break;
else
stack_operand.push(symbol);
}
}
/*下面的else if和else为规则(6)*/
else if((stack_symbol.peek().equals("+")||stack_symbol.peek().equals("-"))&&(string_array[i].equals("*")||string_array[i].equals("/"))){
stack_symbol.push(string_array[i]);
}
else{
stack_operand.push(stack_symbol.pop());
stack_symbol.push(string_array[i]);
}
}else{
stack_operand.push(string_array[i]); //(1)
}
}
/*下面while循环用规则(7)*/
while(true){
if(stack_symbol.isEmpty())
break;
else
stack_operand.push(stack_symbol.pop());
}
String string_epilogue="";
for(String str:stack_operand){ //把后序表达式栈转为后序字符串
string_epilogue+=str+" ";
}
System.out.println(string_epilogue);
return string_epilogue;
}
/*扫描后序算术表达式;
* 扫描到操作数直接压入栈 - - - -(1)
* 扫描到"+","-","*","/",将栈的栈顶的两个操作数压出,压出的两个操作数和扫描到的符号组合成四元式,再将结果压入栈 - - - -(2)
* */
public String getSiYuanShi(String string){
String SiYuanShiString="";
String[] string_array=string.split(" ");
Stack<String> stack=new Stack<>();
int result_num=0;
String result="T";
for(int i=0;i<string_array.length;i++){ //开始扫描字符串数组
if(string_array[i].equals("+")||string_array[i].equals("-")||string_array[i].equals("*")||string_array[i].equals("/")){
result_num++;
result+=result_num;
SiYuanShiString+="("+string_array[i]+","+stack.pop()+","+stack.pop()+","+result+")\n";
stack.push(result);
result="T";
}else{
stack.push(string_array[i]);
}
}
return SiYuanShiString;
}
}
算术表达式
下面是执行结果
第一行是中序转后序需要的格式
第二行是转为后序的算术表达式
具体算法实现,代码里面有详细注释,这里说一下大概过程;
在文件中获取字符串方式就省略了,获取到要翻译的算术表达式字符串之后,转化为一种后面算法所需要的格式,比如5*(52-3)转化为的格式是:5 * ( 52 - 3 ),这一步转化在上面的代码里的方法是toStanderd(String string),转化之后获得的字符串如:第三张图里面第一行字符串,字符串仍然是中序,接下来转化为后序,用到方法getEgilogue(String string),转化为后序之后如:第三张图的第二行字符串。将后序转化为四元式用到的方法getSiYuanShi(String string)。
以上方法具体实现看上面代码,有详细注释。用到了java里面的Stack类以及压栈,出栈和返回栈顶元素的方法。
翻译的算术表达式和翻译结果是图一和图二。
如果看不懂算法注释,可以参考该链接里面的算法http://blog.csdn.net/u012507347/article/details/52245233