A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

一边学车一边看视频,只有晚上有空,真痛苦。。有木有同样境遇的同学。。。。
今天中午看完了毕老师的基础视频,受益匪浅啊,感觉java和C++差的真多。。比如for循环
  1. for(int i = 0;i < 100; i ++){
  2.                         int x = i + 1;
  3.                         //....
  4.                 }
复制代码
Java虚拟机在每次for循环开始都会在栈中开辟新变量x,每次循环结束都会销毁x。而C++只会执行一次int x,以后每次for循环只会执行x = i + 1。效率差距好大。。
进入正题,中午领了阳哥的技术分活动21期,受此激发就做了一个计算器,以前java课程设计也做过计算器,但是都是“简单版”的,最近看毕老师视频看的豪气干云,就狠心要写一个“相对高级版”的。可以处理像“(2.99-4.32)*(90.8-78.66)+78.0/3.14”这样的所有书写正确的表达式。
都是泪啊,一个 if(Stack<String>.peek() =="(")低级错误调试了一个多小时。。C++习惯改不过来。。

核心计算代码分析.
  输入完成,点击"=键"的时候,会拿到一个中缀表达式字符串比如"a + b * c + ( d * e + f ) * g ",写算法的时候中缀不方便计算,要先转换成后缀表达式为"a b c * + d e * f  + g * +",然后利用栈操作计算,更详细的说明在这里 http://www.cnblogs.com/ifinver/p/4017969.html
核心计算类:
  1. public class MyMainAlgorithm {
  2.         public MyMainAlgorithm(){}
  3.         /**
  4.          * 暴露出去的方法,本类仅有这一个public方法,其他方法都为此方法服务
  5.          * @param str 从输入文本框获取的计算表达式
  6.          * @return 计算的结果,字符串形式
  7.          */
  8.         public String getAnswer(String str){
  9.                 //输入为空不计算,比如不输入就直接点“=键”
  10.                 if(str == null || str.equals(""))
  11.                         return "0.";
  12.                
  13.                 String ans = "";
  14.                 //首先判断表达式中的括号是否匹配
  15.                 if(!isWellBracket(str))
  16.                         ans = "输入的表达式括号不匹配";
  17.                 //判断是否为正确的表达式,防止类似连续两个+号的情况等等
  18.                
  19.                 //.....
  20.                
  21.                 //到此假设字符串已经合法 =.= 偷懒了。。
  22.                
  23.                 //中缀表达式变为后缀表达式,用Stack模拟栈
  24.                 Stack<String> preAns = changeToHouzhui(str);
  25.                
  26.                 //计算这个后缀表达式
  27.                 ans = calculat(preAns) + "";
  28.                
  29.                 return ans;
  30.         }       
  31.         private double calculat(Stack<String> preAns){
  32.                 double ans = 0.0;
  33.                 //倒置栈
  34.                 Stack<String> ss = new Stack<String>();
  35.                 while(!preAns.isEmpty())
  36.                         ss.push(preAns.pop());
  37.                 //从表达式栈取出数字压入结果栈,取的是操作符就取出两个元素计算
  38.                 Stack<Double> sd = new Stack<Double>();
  39.                 String str;
  40.                 while(!ss.isEmpty()){
  41.                         str = ss.pop();
  42.                         //是操作符就把结果栈的数字取出来两个进行操作,
  43.                         //注意  原栈倒置过,现在取出又压入了结果栈,又从结果栈拿出进行计算,所以后取出的是操作数
  44.                         //先从sd中取出的是被操作数。
  45.                         if(str.length() == 1 && isOperator(str.charAt(0))){
  46.                                 sd.push(bind(sd.pop(),sd.pop(),str.charAt(0)));
  47.                         }else{//不是操作符就把数压入结果栈
  48.                                 sd.push(new Double(str));
  49.                         }               
  50.                 }
  51.                 ans = sd.peek().doubleValue();
  52.                 return ans;
  53.         }
  54.         private Double bind(Double d2,Double d1,char op){
  55.                 Double res = null;
  56.                 switch(op){
  57.                 case '+':
  58.                         res = d1+d2;
  59.                         break;
  60.                 case '-':
  61.                         res = d1-d2;
  62.                         break;
  63.                 case '*':
  64.                         res = d1*d2;
  65.                         break;
  66.                 case '/':               
  67.                         res = d1/d2;
  68.                         break;
  69.                 }
  70.                 return res;
  71.         }
  72.         //中缀表达式转成后缀表达式
  73.         private Stack<String> changeToHouzhui(String str){
  74.                 //System.out.println(str);
  75.                 //--------------------------
  76.                 //将数和操作符分开        ,存在队列中
  77.                 LinkedList<String> queue = new LinkedList<String>();
  78.                
  79.                 StringBuilder num = new StringBuilder();
  80.                 for(int i = 0;i < str.length();i ++){
  81.                         char c = str.charAt(i);
  82.                         if(!isOperator(c)){
  83.                                 num.append(c);
  84.                         }else{
  85.                                 if(num.length() != 0){
  86.                                         queue.addLast(num.toString());
  87.                                         num.delete(0, num.length());
  88.                                 }
  89.                                 queue.addLast(c+"");
  90.                         }
  91.                 }
  92.                 if(num.length() != 0)
  93.                         queue.addLast(num.toString());
  94.                 //System.out.println(queue);
  95.                 //------------------------
  96.                 //开始转换
  97.                 Stack<String> numStack = new Stack<String>();//存后缀表达式的栈
  98.                 Stack<String> operatorStack = new Stack<String>();//存操作符的栈
  99.                
  100.                 Iterator<String> is = queue.iterator();
  101.                 while(is.hasNext()){
  102.                         String s = is.next();
  103.                         if(s.equals("(")){
  104.                                 operatorStack.push(s);
  105.                         }
  106.                         else if(s.equals(")")){
  107.                                 while(!operatorStack.empty() && !operatorStack.peek().equals("("))
  108.                                         numStack.push(operatorStack.pop());       
  109.                                 if(!operatorStack.empty())
  110.                                         operatorStack.pop();//弹出"("
  111.                         }else if(s.equals("+") || s.equals("-")){
  112.                                 if(operatorStack.empty() || operatorStack.peek().equals("("))
  113.                                         operatorStack.push(s);
  114.                                 else{
  115.                                         while(!operatorStack.empty() && !operatorStack.peek().equals("(")){
  116.                                                 numStack.push(operatorStack.pop());
  117.                                         }
  118.                                         operatorStack.push(s);                                       
  119.                                 }
  120.                         }else if(s.equals("*") || s.equals("/")){
  121.                                 if(operatorStack.empty() ||
  122.                                                 operatorStack.peek().equals("+") ||
  123.                                                 operatorStack.peek().equals("-")||
  124.                                                 operatorStack.peek().equals("(")){
  125.                                         operatorStack.push(s);
  126.                                 }else{
  127.                                         numStack.push(operatorStack.pop());
  128.                                         operatorStack.push(s);
  129.                                 }
  130.                         }else{
  131.                                 numStack.push(s);
  132.                         }
  133.                 }
  134.                        
  135.                 while(!operatorStack.empty()){//如果操作符栈中还有,就都压入表达式栈
  136.                         if(!operatorStack.peek().equals("(")){
  137.                                 numStack.push(operatorStack.pop());
  138.                         }
  139.                 }
  140.                 //System.out.println(numStack);
  141.                 return numStack;
  142.         }
  143.         private boolean isOperator(char c){
  144.                 if(c >= '0' && c <= '9' || c == '.')
  145.                         return false;
  146.                 return true;
  147.         }
  148.         /**
  149.          * 检查输入字符串中的括号是否匹配
  150.          * 可以利用栈简单实现,
  151.          * 即遇到'('进栈,遇到')'就从栈中弹出一个元素,直到表达式结束。
  152.          * 如果栈为空则表示括号匹配,否则不匹配
  153.          *
  154.          * @param str
  155.          * @return
  156.          */
  157.         private boolean isWellBracket(String str){
  158.                 Stack<String> stack = new Stack<String>();
  159.                 for(int i = 0;i < str.length();i ++){
  160.                         char c = str.charAt(i);
  161.                         if(c == '(')
  162.                                 stack.push(c+"");
  163.                         else if(c == ')'){
  164.                                 if(stack.isEmpty())
  165.                                         return false;
  166.                                 stack.pop();
  167.                         }
  168.                 }
  169.                 return stack.isEmpty();
  170.         }
  171. }
复制代码





先封装了一个用JFrame做的界面 MyWindow,它的init()方法把传入Listener添加在按钮和文本框上:
  1. public class MyWindow extends JFrame {
  2.         private JTextField jti = new JTextField(20);// 输入文本框
  3.         private JTextField jto = new JTextField(20);//显示结果的文本框
  4.         private JButton[] jb = new JButton[27];
  5.         private String[] arr = {"7", "8", "9", "/", "CE",
  6.         "4", "5", "6", "*","(","1","2","3", "+",")","0",".","C","-","=" };
  7.         private JPanel jp = new JPanel();// 主面板
  8.         private JPanel m = new JPanel();// 次面板
  9.         private GridLayout glo = new GridLayout(6, 1, 3, 3);// 主网格布局
  10.         private GridLayout glo1 = new GridLayout(1, 5, 4, 4);// 次网格布局

  11.         protected MyWindow(){}
  12.         //初始化界面,传入一个键盘监听类和动作监听类
  13.         protected void init(KeyListener kl,ActionListener al) {}
  14.         //得到输入的表达式字符串
  15.         protected String getInput(){}
  16.         //在文本框里显示字符串
  17.         protected void setAnswer(String ans){}
  18.         //清除输入,比如点击"CE"键
  19.         protected void clearInput(){}
  20.         //回退一个输入,比如点击"C"键
  21.         protected void backspace(){}
  22.         //向输入文本框里输入字符串
  23.         protected void type(String str){}
  24. }
复制代码

按钮动作监听类
  1. public class MyActionListener implements ActionListener{

  2.         private MyWindow mw;
  3.         protected MyActionListener(MyWindow my){
  4.                 this.mw = my;
  5.         }
  6.         /**
  7.          * 点击按钮动作
  8.          */
  9.         @Override
  10.         public void actionPerformed(ActionEvent e) {
  11.                 // TODO Auto-generated method stub
  12.                 JButton btn = (JButton)e.getSource();
  13.                 String cmd = btn.getText();
  14.                 if("=".equals(cmd)){
  15.                         //点击=按钮时计算结果
  16.                         MyMainAlgorithm mma = new MyMainAlgorithm();
  17.                         String str = mma.getAnswer(mw.getInput());
  18.                         mw.setAnswer(str);//将结果显示在结果文本框里
  19.                 }else if("CE".equals(cmd)){
  20.                         mw.clearInput();//清空输入
  21.                 }else if("C".equals(cmd)){
  22.                         mw.backspace();//回退一个字符
  23.                 }else{
  24.                         mw.type(cmd);
  25.                 }
  26.         }
  27. }
复制代码

键盘监听类,偷懒了。。
  1. public class MyKeyListener extends KeyAdapter {
  2.         private MyWindow mw;
  3.         protected MyKeyListener(MyWindow my){
  4.                 this.mw = my;
  5.         }
  6.         /**
  7.          * 在输入框里按下字符处理code
  8.          */
  9.         @Override
  10.         public void keyTyped(KeyEvent e) {
  11.                 // TODO Auto-generated method stub
  12.                 //懒的写了,直接截死了。
  13.                 mw.setAnswer("懒的写键盘处理code了,就用鼠标点把。");
  14.                 new Thread(new Runnable(){
  15.                         @Override
  16.                         public void run() {
  17.                                 // TODO Auto-generated method stub
  18.                                 try {
  19.                                         Thread.sleep(900);
  20.                                 } catch (InterruptedException e) {
  21.                                         // TODO Auto-generated catch block
  22.                                         e.printStackTrace();
  23.                                 }
  24.                                 mw.setAnswer("0.");
  25.                         }                       
  26.                 }).start();
  27.                 e.consume();
  28.         }
  29. }
复制代码

主函数
  1. public class MyCalculator {

  2.         public static void main(String[] args) {
  3.                 // TODO Auto-generated method stub
  4.                 MyWindow w = new MyWindow();
  5.                
  6.                 MyActionListener mal = new MyActionListener(w);
  7.                 MyKeyListener mkl = new MyKeyListener(w);
  8.                
  9.                 w.init(mkl, mal);
  10.                
  11.                 w.setVisible(true);
  12.                

  13.         }

  14. }
复制代码

附上整个项目,javaSE1.7的

游客,如果您要查看本帖隐藏内容请回复




评分

参与人数 2技术分 +3 黑马币 +6 收起 理由
杨佳名 + 3 大赞一下!
水竹 + 6

查看全部评分

13 个回复

倒序浏览
活捉大神一枚{:3_54:}
回复 使用道具 举报
这完全是大神的节奏啊,看视频的时候能写出这样的代码,我现在看完了都看不太懂大神的代码啊...你一定是匹好黑马,加油!
回复 使用道具 举报
大婶一个
回复 使用道具 举报
这哥们写嗨了都……
回复 使用道具 举报
LFW 中级黑马 2014-10-10 23:23:40
地板
哇塞,好多神呼呼的代码
回复 使用道具 举报
我去,这也太牛了吧,看来基础杠杠的好,我等零基础屌丝还得努力啊,虽然很努力在学了,但是差距还是很大
回复 使用道具 举报
ifinver 中级黑马 2014-10-10 23:32:44
8#

嘿嘿,我是刚看完毕老师java基础视频的菜鸟-。-只是有些C++基础。。
明天开始看张老师的java高新技术。。。
成为大神的路还好长的说0.0
回复 使用道具 举报
ifinver 中级黑马 2014-10-10 23:34:16
9#
hollywood2014 发表于 2014-10-10 22:47
这完全是大神的节奏啊,看视频的时候能写出这样的代码,我现在看完了都看不太懂大神的代码啊...你一定是匹 ...

大二大三做了2年C++C#,所以有点像“开小灶”吧。。嘿嘿、
加油,一起学习。
回复 使用道具 举报
水竹 发表于 2014-10-10 23:20
这哥们写嗨了都……

看毕老师视频更嗨。。。。。=。=
回复 使用道具 举报
jeromechen 发表于 2014-10-10 23:28
我去,这也太牛了吧,看来基础杠杠的好,我等零基础屌丝还得努力啊,虽然很努力在学了,但是差距还是很大 ...

多写就好啦,我java也是0基础。。敲行代码敲半天。。主要是学会了怎么查API基础就算过关了把-。-
回复 使用道具 举报
感谢楼主分享!
回复 使用道具 举报
周波 来自手机 中级黑马 2014-10-11 08:19:57
13#
这也敢称新人,让我们情何以堪
回复 使用道具 举报
这也叫新人
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马