目录

  • 基本工具
  • 基础内容
  • Hello World 和 模块分解
  • 数组的使用
  • 命令行参数
  • 递归
  • 分支语句
  • String类的使用
  • 类的定义与测试
  • 多态
  • IO与异常
  • 数据库
  • 网络与安全
  • 数据结构应用
  • Android

做了几年教学改革,理论和形式上我感觉基本完备了:

很重要的一点是厘清“教是老师的责任,学是学生的责任”,也就是“老师当教练,学生做中学”。

有了SPOC平台蓝墨云班课 ,教学工具上也基本完善了:

我在程序设计学习上有一个基本的体会是:

  • 开始不会编程,最好的学习方式是抄教材,敲代码,还专门写了一篇指导《积极主动敲代码,使用Junit学习Java程序设计》,我认为积极主动敲5000行左右的代码,应该能解决基本语法的问题,基本程序设计的问题,基本工具(git,jdb,junit,idea...)的使用问题

  • 然后独立编写5000行左右的代码,解决程序逻辑错误的调试,模块分解,问题解决的一般过程等相关问题

  • 有了10000行代码的基础,后面的学习提高要依靠代码阅读了,比如JUnit的源码,JHotdraw的源码,Java Collection API的源码,Java JCE的源码等

教学中也是想通过这三个步骤进行训练。

看了范飞龙博士(博客,微博)的“如何设计题目”和“近发展区/脚手架”,一方面感觉龙博不当老师真是亏了,另一方面是感觉自己的题目设计上还有改进的空间。

这篇指导想参考龙博的博客,解决第二层次的问题,从Hello World通过一个个小练习不断迭代,来一步一步提高大家使用Java来解决具体问题的能力。

返回目录

基本工具

这里面的工具每周都要求使用,我们同学的博客上也都提交了会使用的证据,课上默认大家熟练掌握了,没有掌握的课下努力了。

  • 程序开发与信息安全工具箱
  • 使用博客园进行学习
  • 使用开源中国托管代码
  • Java程序设计的DOS命令基础
  • 别出心裁的Linux命令学习法
  • 使用码云和博客园学习简易教程
  • Intellj IDEA 简易教程
  • 使用JDB调试Java程序
  • 进度条和学习过程可视化

返回目录

基础内容

这些内容在实验课上都做过了,同学们也都提交了自己掌握了的证据,我们在课堂实践测试时每次都会使用相关内容。

  • 实验一 Java开发环境的熟悉

    • 命令行下Java程序编译,运行,调试
    • IDE下Java程序编译,运行,调试
  • 实验二 Java面向对象程序设计
    • 伪代码,产品代码,测试代码
    • JUnit的使用
    • UML建模
  • 实验三 敏捷开发与XP实践
    • 代码标准
    • 结对编程
    • git
    • 重构

返回目录

Hello World 和 模块分解

由Kernighan和Ritchie合著的经典教程《The C Programming Language》的开篇第一个C程序例子是打印简单的“Hello World!”。从此之后,“Hello World”就成了描述人们编写的第一个程序的代名词---不管你用什么编程语言。

简单的“Hello World”能够运行出来,说明你的开发环境是没有问题的,这就有了进一步学习的基础。通过“Hello World”程序你也能初步理解程序的基本结构。

Java程序设计也不例外,我们从"Hello World"起步,来看看你的开发环境是不是准备好了。如果开发环境都没有准备好,你号称本学期写了几千行代码基本上就可以归零了。

开发环境的准备有命令行和IDE两种,大家都要掌握,后面的练习会用到命令行和IDE,前面没有掌握好的复习上面的基础内容。

Java中的Hello World程序HelloWorld.java如下:

public class HelloWorld {public static void main(String[] args){System.out.println("Hello World!");}
}

我在Linux命令行中可以用javac HelloWorld.java进行编译上面的程序,用java HelloWorld运行上面的程序:

教材已经学习完毕,我们知道Java中子系统是以包实现的,我们现在写个带包的Hello World:

package ljp.is.besti.edu.cn;public class HelloWorld {public static void main(String[] args){System.out.println("Hello World!");}
}

这时候,用javac编译时要加上-d参数,用java运行时类名前要加上包前缀:

为了方便管理实践考试代码,建议同学们建立一个以自己学号命名的文件夹,每次实践考试都要提交这个文件夹的码云链接.
我们养成在项目根目录下也就是2015520ljp文件夹下工作的习惯,这时候通过 javac -d bin src/HelloWorld.java把class文件编译到bin文件夹下,运行时要加上-cp或-classpath参数:

Java程序员有两个角色:

  • 类设计者
  • 类使用者

对一个模块,我们要设计出来一个类,还要有一个测试类,这个测试类是一个带main的public类

  • XXXX.java
  • XXXXTester.java
    • 带main

第一个任务是设计一个HelloWorld类,里面有一个方法public static void printHello()打印出“Hello World”字符串,在HelloWorldTester类补充代码调用printHello。

HelloWorld.java:

package ljp.is.besti.edu.cn;public class HelloWorld {public static void sayHello(){System.out.println("Hello World!");}
}

HelloWorldTester.java:

package ljp.is.besti.edu.cn;public class HelloWorldTester {public static void main(String[] args){//补充代码调用printHello...}
}

下面是补充好的代码和编译运行过程:

package ljp.is.besti.edu.cn;public class HelloWorldTester {public static void main(String[] args){//补充代码调用printHelloHelloWorld.sayHell();}
}

返回目录

数组的使用

算法设计中很重要的一点是临时变量的使用。比如,我们定义了两个变量int a=5;int b=6; 我们怎么把a和b的值交换一下? 不少程序设计的初学者的做法是:

a = b;
b = a;

这样是不能实现两个变量的交换的,执行完第一条语句a的值为6,b的值也为6,执行完第二条语句之后a的值为6,b的值也为6,没什么变化。

正确的做法是定义一个临时变量:

int tmp = a;
a = b;
b = tmp;

不使用临时变量也有办法实现交换,参考交换两个变量的值,不使用第三个变量的四种法方法,那样代码不清晰,我们不提倡使用。

程序设计中有三种语句:

  • 顺序语句
  • 分支语句
  • 循环语句

我们解决问题时要提高抽象能力,要多使用循环解决问题,分支只是用来解决特殊情况的。

通过使用数组来学习循环的使用。

Java中遍历数组,for-each语法很好用:

  //定义一个数组,比如int arr[] = {1,2,3,4,5,6,7,8};//打印原始数组的值for(int item:arr){System.out.print(item + " ");}System.out.println();

我们还可以从前往后遍历数组:

  //定义一个数组,比如int arr[] = {1,2,3,4,5,6,7,8};//打印原始数组的值for(int i=0; i<arr.length; i++){System.out.print(arr[i] + " ");}System.out.println();

我们还可以从后往前遍历数组:

  //定义一个数组,比如int arr[] = {1,2,3,4,5,6,7,8};//打印原始数组的值for(int = arr.lenth; i>0; i--){System.out.print(arr[i-1] + " ");}System.out.println();

实践任务:

  //定义一个数组,比如int arr[] = {1,2,3,4,5,6,7,8};//打印原始数组的值for(int i:arr){System.out.print(i + " ");}System.out.println();// 添加代码删除上面数组中的5...//打印出 1 2 3 4 6 7 8 0for(int i:arr){System.out.print(i + " ");}System.out.println();// 添加代码再在4后面5...//打印出 1 2 3 4 5 6 7 8for(int i:arr){System.out.print(i + " ");}System.out.println();

删除一个元素时比较容易,插入时就要用到临时变量了,当然,你可以从数组的最后一个元素开始移动,就避免了临时变量的使用。

参考代码:

  1 public class ArrayOperation {23     public static void main(String [] args){4         int arr[] = {1,2,3,4,5,6,7,8};56         for(int i:arr){7             System.out.print(i + " ");8         }9         System.out.println();1011         for(int i=5; i<arr.length; i++)12             arr[i-1] = arr[i];1314         arr[7] = 0;1516         for(int i:arr){17             System.out.print(i + " ");18         }19         System.out.println();2021         for(int i=arr.length; i>4; i--)22             arr[i-1] = arr[i-2];2324         arr[4] = 5;2526         for(int i:arr){27             System.out.print(i + " ");28         }29         System.out.println();3031     }32 }

返回目录

命令行参数

我们再回到Hello World程序:

public class HelloWorld {public static void main(String[] args){System.out.println("Hello World!");}
}

以前只是说大家只要记住main方法的写法,现在要能深入理解了,“public static void”是什么意思要清楚。我们这里要说的是main方法的参数 String [] args. args是一字符串数组,它是从哪里来的?Java程序运行时,会调用main方法,args就是命令行参数。

我们写一个测试程序CommandLine.java:

  1 public class CommandLine {2     public static void main(String [] args) {3         for(String arg : args){4             System.out.println(arg);5         }6     }7 }

我们java CommandLine运行时,没有什么输出。

我们java CommandLine 1 2 3运行时,输出如下图,此时 args[0]=="1", args[1]=="2", args[2]=="3",args.lenth == 3。

在IDEA这种IDE中如何传递命令行参数?我们选择Run->Edit Configuration...

命令行中的参数通过 Programm argumetns传递。

实践内容

提交测试结果截图,课下把代码上传到码云。
求命令行传入整数参数的和。
public class CLSum {public static void main(String [] args) {int sum = 0;// 参考Integer类中的方法把字符串转为整数// 补充代码求命令行参数的args中整数数据的和...// 打印 System.out.println(sum);}
}

参考代码:

public class CLSum {public static void main(String [] args) {int sum = 0;// 参考Integer类中的方法把字符串转为整数// 补充代码求命令行参数的args中整数数据的和for(String arg: args)sum += Interger.parseInt(arg);// 打印 System.out.println(sum);}
}

有同学想先把传入的字符串数组转化为一个临时的int 数组,可以这样:

  1 public class CLSum1 {2     public static void main(String [] args) {3         int sum = 0;45         int [] tmp = new int [args.length];6         for(int i=0; i<args.length; i++) {7             tmp[i] = Integer.parseInt(args[i]);8         }910         for(int t : tmp){11             sum += t;1213         }1415         System.out.println(sum);16     }17 }

同学们还有遇到Integer类中没有parseInt()的问题,这是我们实验二定义了自己的Integer等类,与Java重名了,就和两个班有重名的同学一样,区分必须加上班级名,我们这就要加上包名java.lang.Integer。

返回目录

递归

递归算法是一种直接或间接地调用自身的算法。在编写程序时,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于理解。

递归用于解决形式相同,规模不同的问题,能用递归解决的问题都可以转化为循环。递归把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。用递归思想写出的程序往往十分简洁易懂。

递归程序有两个要点:递归公式和结束条件。我们以求整数的阶乘为例:

有了公式,代码就容易写出来了:

  1 public class Factorial {2     public static void main(String [] args) {3         System.out.println(fact(5));4     }56     public static int fact(int n) {7         if (n == 0)8             return 1;9         else10             return n * fact(n-1);11     }12 }

fact(5)的递推过程如下图:

JDB不但是个调试工具,还是一个学习工具,参考 《使用JDB调试Java程序》的递归调试部分,看看递归调用的动态过程。

实践:

public class CLSumRecursion {public static void main(String [] args) {int sum = 0;// 参考Integer类中的方法把字符串转为整数// 补充代码以递归的方式求命令行参数的args中整数数据的和...// 打印 System.out.println(sum);}//递归函数public static int  clSum(int [] arr) {...}
}

参考代码:

  1 import java.util.Arrays;23 public class CLSumRecursion {4     public static void main(String [] args) {5         int sum = 0;67         if(args.length < 1){8             System.out.println("Usage: java CLSumRecursion num1 num2 ...");9             System.exit(0);10         }1112         int [] tmp = new int [args.length];13         for(int i=0; i<args.length; i++) {14             tmp[i] = Integer.parseInt(args[i]);15         }1617         sum =  clsum(tmp);18         System.out.println(sum);19     }2021     public static int clsum(int [] arr)22         if (arr.length == 1)23             return arr[0];24         else {25             int [] tmp = Arrays.copyOf(arr, arr.length-1);26             return clsum(tmp) + arr[arr.length-1];27         }28     }29 }

这个题目出的不太好,用递归求1+2+3+...+N就容易理解些:

int sum(int n){if (n==1)return 1;elsereturn sum(n-1) + n;
}

返回目录

分支语句

相对于顺序语句来说,分支语句多用于处理特殊情况,Java中的分支语句有:

  • if... else if ... else
  • switch...case
    • jdk8中switch 可以是字符串类型
    • 每个case中不要忘了break

这两个语句是等价的。

使用分支语句时要注意MESE原则,MESE是Mutually Exclusive Collectively Exhaustive的缩写,意思是“相互独立,完全穷尽”。 也就是对于问题的分类要能够做到不重叠、不遗漏。if中的else, switch...case中的default对于不遗漏.

实践:

实现一个简易计算器Calc,支持+ - x / 和%运算, 从命令行传入计算数据,比如:java Calc 2 + 3     结果为 2 + 3 = 5
java Calc 8 - 3     结果为 8 - 3 = 5
java Calc 2 x 3     结果为2 x 3 = 6
java Calc 10 / 2     结果为10 / 2 = 5
java Calc 10 % 3     结果为10 % 3 = 11 public class Calc {2     public static void main(String [] args) {34         int result = 0;56         if (args.length != 3) {7             System.out.println("Usage: java Calc operato1 operand(+ - X / %) operator2");8         }9         //======以下补充代码=====10         //+ - x / 和%运算         11         //======以上补充代码======12         System.out.println(args[0] + " " + args[1] + " " + args[2] + " = " + result);1314     }15 }

参考代码如下:

  1 public class Calc {2     public static void main(String [] args) {34         int result = 0;56         if (args.length != 3) {7             System.out.println("Usage: java Calc operato1 operand(+ - x / %) operator2");8         }910         switch (args[1]) {11         case "+":12             result = Integer.parseInt(args[0]) + Integer.parseInt(args[2]);13             break;14         case "-":15             result = Integer.parseInt(args[0]) - Integer.parseInt(args[2]);16             break;17         case "x":18             result = Integer.parseInt(args[0]) * Integer.parseInt(args[2]);19             break;20         case "/":21             result = Integer.parseInt(args[0]) / Integer.parseInt(args[2]);22             break;23         case "%":24             result = Integer.parseInt(args[0]) % Integer.parseInt(args[2]);25             break;26         default:27             System.out.println("Usage: java Calc operato1 operand(+ - x / %) operator2");28             break;2930         }31         System.out.println(args[0] + " " + args[1] + " " + args[2] + " = " + result);3233     }34 }

这个代码要注意的是乘法在命令行参数中不能用“*”, "*"是一个通配符,会返回当前目录的所有文件名。

还有同学拷贝上面的代码后要一行一行的删除行号,如果用Vim的话,使用列模式很容易就把删除了,Vim 中我们使用 Ctrl+v 进入列模式,选择前两列,按x就删除了。

IDEA中也支持Vim模式,熟悉Vim的同学可以安装IDEAVim插件:

String类的使用

我们通过String类的使用为例说明程序设计的几个问题

  • 程序设计是用来解决问题的,问题驱动的方式是个好的学习方式
  • 解决问题不是所有问题都要自己解决,可以借助类库,API等通过代码复用来加快开发
  • 要养成写伪代码,产品代码,测试代码的习惯

我们先回顾一个Linux命令sort:

我们关注下面几个选项:

-t<分隔字符>:指定排序时所用的栏位分隔字符;
-k: 针对第几列进行排序
-n:依照数值的大小排序;
-r:以相反的顺序来排序; 

如何实现Linux下Sort的功能对一个字符串数组进行排序?你可能学习过或者听说过冒泡排序,归并排序,插入排序,选择排序,快速排序等算法,我们要先实现这些算法吗?Java编程中我们可以先查查API文档:

我们发现java.util.Arrays类和java.util.Collections类中都实现了sort方法,我们不用自己编程实现排序算法了,调用这些方法就可以了。

调用java.util.Arrays.sort的示例:

  1 import java.util.*;23 public class MySort1 {4     public static void main(String [] args) {5         String [] toSort = {"aaa:10:1:1",6                             "ccc:30:3:4",7                             "bbb:50:4:5",8                             "ddd:20:5:3",9                             "eee:40:2:20"};1011         System.out.println("Before sort:");12         for (String str: toSort)13                     System.out.println(str);1415         Arrays.sort(toSort);1617         System.out.println("After sort:");18         for( String str : toSort)19             System.out.println(str);20     }21 }

调用java.util.Collections.sort的示例:

  1 import java.util.*;23 public class MySort1 {4     public static void main(String [] args) {5         String [] toSort = {"aaa:10:1:1",6                             "ccc:30:3:4",7                             "bbb:50:4:5",8                             "ddd:20:5:3",9                             "eee:40:2:20"};1011         System.out.println("Before sort:");12         for (String str: toSort)13                     System.out.println(str);1415         List<String> list = new ArrayList();16         for (String str: toSort)17             list.add(str);1819         Collections.sort(list);2021         System.out.println("After sort:");22         for( String str : list)23             System.out.println(str);24     }25 }

实践任务:

  • 模拟实现Linux下Sort -t : -nk 4的功能,补充第17,25行代码。提交码云链接和代码运行截图。
  1 import java.util.*;23 public class MySort {4     public static void main(String [] args) {5         String [] toSort = {"aaa:10:1:1",6                             "ccc:30:3:4",7                             "bbb:50:4:5",8                             "ddd:20:5:3",9                             "eee:40:2:20"};1011         System.out.println("Before sort:");12         for (String str: toSort)13                     System.out.println(str);1415         Integer [] tmp = new Integer [toSort.length];16         for(int i=0; i<tmp.length; i++)17             tmp[i] = ...;1819         Arrays.sort(tmp);2021         System.out.println("After sort:");2223         for(int i=0; i<tmp.length; i++)24             for(int j=0; j<toSort.length; j++)25                 if(...)26                     System.out.println(toSort[j]);27     }28 }

参考代码

 1 import java.util.*;23 public class MySort {4     public static void main(String [] args) {5         String [] toSort = {"aaa:10:1:1",6                             "ccc:30:3:4",7                             "bbb:50:4:5",8                             "ddd:20:5:3",9                             "eee:40:2:20"};1011         System.out.println("Before sort:");12         for (String str: toSort)13                     System.out.println(str);1415         Integer [] tmp = new Integer [toSort.length];16         for(int i=0; i<tmp.length; i++)17             tmp[i] = new Integer(Integer.parseInt(toSort[i].split(":")[3]));1819         Arrays.sort(tmp);2021         System.out.println("After sort:");2223         for(int i=0; i<tmp.length; i++)24             for(int j=0; j<toSort.length; j++)25                 if(Integer.parseInt(toSort[j].split(":")[3]) == tmp[i].intValue())26                     System.out.println(toSort[j]);27     }28 }

这里面有几个问题:

返回目录

类的定义与测试

返回目录

多态

返回目录

IO与异常

返回目录

数据库

返回目录

网络与安全

返回目录

数据结构应用

《实验二 Java面向对象程序设计》提出编写程序要写三种代码:

  • 伪代码
  • 产品代码
  • 测试代码

我们学习编程是用来解决实际问题的,我们使用《别出心裁的Linux系统调用学习法》中的方法进行学习》

  • 学习一个Linux命令
  • 分析如何实现,写出伪代码
  • 用Java实现Linux命令,写出产品代码
  • 测试自己的实现,写出测试代码

栈的应用

栈 (Stack)是一种只允许在表尾插入和删除的线性表,有先进后出(FILO),后进先出(LIFO)的特点。允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom)。

Java中有Stack类,不熟悉的同学可以参考《积极主动敲代码,使用Junit学习Java程序设计》学习一下:

  • empty()
  • push()
  • pop()

栈的一个应用是用来对四则运算表达式进行求值。

表达式Exp = S1 + OP + S2(S1 ,S2是两个操作数,OP为运算符)有三种标识方法:

  • OP + S1 + S2 为前缀表示法
  • S1 + OP + S2 为中缀表示法
  • S1 + S2 + OP 为后缀表示法

例如:Exp = a * b + (c - d / e) * f

  • 前缀式: + * a b * - c / d e f
  • 中缀式: a * b + c - d / e * f
  • 后缀式: a b * c d e / - f * +

我们可以看出:

  1. 操作数之间的相对次序不变;
  2. 运算符的相对次序不同;
  3. 中缀式丢失了括弧信息,致使运算次序不确定;
  4. 前缀式的运算规则为:连续出现的两个操作数和在它们之前且紧靠它们的运算符构成一个最小表达式;
  5. 后缀式的运算规则为:运算符在式中出现的顺序恰为表达式的运算顺序;每个运算符和在它之前出现且紧靠它的两个操作数构成一个最小表达式。

后缀表示法是波兰逻辑学家J.Lukasiewicz于1929年提出的,又叫做逆波兰表达式。

Linux命令dc可以用来对逆波兰式表达式进行求值,dc的打印类命令:

  • p:打印栈顶元素并换行
  • n: 打印栈顶元素并将其弹出栈,完毕后不换行
  • P: putchar ( int(栈顶元素) % 256) 并弹栈顶,不换行
  • f: 从栈顶至栈底打印栈中所有值,每个一行

dc的运算符:

  • +: 依次弹出w1与w2,将w2+w1压栈。精度为结果值精度
  • -: 依次弹出w1与w2,将w2-w1压栈
  • *: 依次弹出w1与w2,将w2*w1压栈。精度为结果值精度与precision中较大值
  • / : 依次弹出w1与w2,将w2/w1压栈。精度为precision
  • % : 依次弹出w1与w2,将w2-w2/w1*w1压栈
  • ~ : 依次弹出w1与w2,依次将w2/w1与w2%w1压栈
  • ^ : 依次弹出w1与w2,将w2^((int)w1)压栈。精度为w2精度与precision中较大值
  • | : 依次弹出w1 w2与w3,将 w3 ^ ((int)w2) (mod w1) 压栈。w1 w3 需为整数
  • v : 弹出w1,将sqrt(v)压栈。精度为precision

dc支持栈操作:

  • c : 清空栈
  • d : 将栈顶元素复制并压栈
  • r : 交换栈顶两元素 XXX

我们看一下dc如何使用:

我们如何实现dc? 这要用到栈。对逆波兰式求值时,不需要再考虑运算符的优先级,只需从左到右扫描一遍后缀表达式即可。求值伪代码如下:

  • 设置一个操作数栈,开始栈为空;
  • 从左到右扫描后缀表达式,遇操作数,进栈;
  • 若遇运算符,则从栈中退出两个元素,先退出的放到运算符的右边,后退出的放到运算符左边,运算后的结果再进栈,直到后缀表达式扫描完毕。

此时,栈中仅有一个元素,即为运算的结果。

我们给出一个例子,求后缀表达式:1 2 + 8 2 - 7 4 - / * 的值:


MyDC.java: 补充代码31-40行

  1 import java.util.StringTokenizer;2 import java.util.Stack;34 public class MyDC5 {6   /** constant for addition symbol */7   private final char ADD = '+';8   /** constant for subtraction symbol */9   private final char SUBTRACT = '-';10   /** constant for multiplication symbol */11   private final char MULTIPLY = '*';12   /** constant for division symbol */13   private final char DIVIDE = '/';14   /** the stack */15   private Stack<Integer> stack;1617   public MyDC() {18     stack = new Stack<Integer>();19   }2021   public int evaluate (String expr)22   {23     int op1, op2, result = 0;24     String token;25     StringTokenizer tokenizer = new StringTokenizer (expr);2627     while (tokenizer.hasMoreTokens())28     {29       token = tokenizer.nextToken();3031       //如果是运算符,调用isOperator32       if ()33       {34         //从栈中弹出操作数235         //从栈中弹出操作数136         //根据运算符和两个操作数调用evalSingleOp计算result;37         //计算result入栈;38       }39       else//如果是操作数40         //操作数入栈;41     }4243     return result;44   }4546   private boolean isOperator (String token)47   {48     return ( token.equals("+") || token.equals("-") ||49              token.equals("*") || token.equals("/") );50   }5152   private int evalSingleOp (char operation, int op1, int op2)53   {54     int result = 0;5556     switch (operation)57     {58       case ADD:59         result = op1 + op2;60         break;61       case SUBTRACT:62         result = op1 - op2;63         break;64       case MULTIPLY:65         result = op1 * op2;66         break;67       case DIVIDE:68         result = op1 / op2;69     }7071     return result;72   }73 }

测试类,MyDCTester.java ,代码不用修改

  1 import java.util.Scanner;23 public class MyDCTester  {45   public static void main (String[] args) {67     String expression, again;89     int result;1011     try12     {13       Scanner in = new Scanner(System.in);1415       do16       {17         MyDC evaluator = new MyDC();18         System.out.println ("Enter a valid postfix expression: ");19         expression = in.nextLine();2021         result = evaluator.evaluate (expression);22         System.out.println();23         System.out.println ("That expression equals " + result);2425         System.out.print ("Evaluate another expression [Y/N]? ");26         again = in.nextLine();27         System.out.println();28       }29       while (again.equalsIgnoreCase("y"));30     }31     catch (Exception IOException)32     {33       System.out.println("Input exception reported");34     }35   }36 }

参考代码

  1 import java.util.StringTokenizer;2 import java.util.Stack;34 public class MyDC5 {6   /** constant for addition symbol */7   private final char ADD = '+';8   /** constant for subtraction symbol */9   private final char SUBTRACT = '-';10   /** constant for multiplication symbol */11   private final char MULTIPLY = '*';12   /** constant for division symbol */13   private final char DIVIDE = '/';14   /** the stack */15   private Stack<Integer> stack;1617   /**18    * Sets up this evalutor by creating a new stack.19    */20   public MyDC()21   {22     stack = new Stack<Integer>();23   }2425   public int evaluate (String expr)26   {27     int op1, op2, result = 0;28     String token;29     StringTokenizer tokenizer = new StringTokenizer (expr);3031     while (tokenizer.hasMoreTokens())32     {33       token = tokenizer.nextToken();3435       if (isOperator(token))36       {37         op2 = (stack.pop()).intValue();38         op1 = (stack.pop()).intValue();39         result = evalSingleOp (token.charAt(0), op1, op2);40         stack.push (new Integer(result));41       }42       else43         stack.push (new Integer(Integer.parseInt(token)));44     }4546     return result;47   }4849   private boolean isOperator (String token)50   {51     return ( token.equals("+") || token.equals("-") ||52              token.equals("*") || token.equals("/") );53   }5455   private int evalSingleOp (char operation, int op1, int op2)56   {57     int result = 0;5859     switch (operation)60     {61       case ADD:62         result = op1 + op2;63         break;64       case SUBTRACT:65         result = op1 - op2;66         break;67       case MULTIPLY:68         result = op1 * op2;69         break;70       case DIVIDE:71         result = op1 / op2;72     }7374     return result;75   }76 }44     }4546     return result;47   }4849   private boolean isOperator (String token)50   {51     return ( token.equals("+") || token.equals("-") ||52              token.equals("*") || token.equals("/") );53   }5455   private int evalSingleOp (char operation, int op1, int op2)56   {57     int result = 0;5859     switch (operation)60     {61       case ADD:62         result = op1 + op2;63         break;64       case SUBTRACT:65         result = op1 - op2;66         break;67       case MULTIPLY:68         result = op1 * op2;69         break;70       case DIVIDE:71         result = op1 / op2;72     }7374     return result;75   }76 }

大家注意两个private 方法isOperator, evalSingleOp的设计,体会一下方法分解。

对一般人来说,得到后缀表达式就是一件不容易的事。我们习惯的还是中缀表达式。Linux中另外一个计算器bc就是用来计算中缀表达式的:

我们如何编程实现bc? 把中缀式转化后缀式调用MyDC.java 中的evaluate方法就行了。这样问题转化为如何由中缀式求得后缀式?

由中缀式求得后缀式可以使用栈,伪代码如下:

  • 设立一个栈,存放运算符,首先栈为空;
  • 从左到右扫描中缀式,若遇到操作数,直接输出,并输出一个空格作为两个操作数的分隔符;
  • 若遇到运算符,则与栈顶比较,比栈顶级别高则进栈,否则退出栈顶元素并输出,然后输出一个空格作分隔符;
  • 若遇到左括号,进栈;若遇到右括号,则一直退栈输出,直到退到左括号止。
  • 当栈变成空时,输出的结果即为后缀表达式。

将中缀表达式 (1+2)*((8-2)/(7-4)) 变成后缀表达式,栈的变化及输出结果:


算符优先法求解表达式:(生成后缀表达式+后缀表达式求值)

  • 步骤1:建立符号运算的优先级关系表

  • 步骤2

    • (1) 设操作数栈OPND,置空;运算符栈OPTR,最低符号#压进OPTR;
    • (2) 读入字符C,C若是操作数, 进OPND;若是运算符,与OPTR栈顶元素(A)比较,根据算符优先级,决定如何处理:
      • A<C, C压入OPTR栈;
      • A=C, A从OPTR出栈;
      • A>C,A出栈,从OPND依次弹出两个操作数y、x, 计算Z=x A y,Z压入OPND栈。C压进OPTR.
    • (3) 重复(2),直至表达式结束。

返回目录

Android开发

返回目录


  • 原文地址:http://www.cnblogs.com/rocedu/p/6766748.html

  • 推荐网站:博客园、新浪微博、扇贝背单词、DKY背单词小组、有道云笔记、豆瓣读书

  • 版权声明:自由转载-非商用-非衍生-保持署名| Creative Commons BY-NC-ND 3.0


如果你觉得本文对你有帮助,请点一下左下角的“好文要顶”和“收藏该文


2016-2017-2 《Java 程序设计》课堂实践项目相关推荐

  1. 20155322 《Java程序设计》课堂实践项目 数据库-3-4

    20155322 <Java程序设计>课堂实践项目 数据库-3-4 数据库-3 实践要求 参考教材代码完成下面的要求,提交能连接到world的截图(有学号水印),并提交代码的码云链接.查询 ...

  2. java程序设计教程与项目_Java程序设计教程与项目实训

    书名:Java程序设计教程与项目实训 作者:温秀梅.司亚超 出版社:清华大学出版社 出版日期:2017/8/1 字数: 页数: 版次: ISBN:9787#302473701 定价:49.5 目录 章 ...

  3. java程序设计与实践教程 王薇 doc_Java程序设计与实践教程 王薇主编 答案

    Java程序设计与实践教程 王薇 主编 董迎红 副主编 课后习题 答案 第1章 JAVA简介 一.判断题 1.√ 2.√ 3. 4. 5. 6.√ 7.√ 8.√ 9. 10. 二.填空题 1.App ...

  4. java程序设计及实践实践代码_杭+新闻:姚争为老师把程序设计讲“活”了,满是代码的枯燥课程被学生“秒杀”...

    通讯员 陈鑫 杨鹏飞 记者 方秀芬 作为专业选修课,Java程序设计和Web程序设计,这两门满是代码的课程,看似很枯燥,但在杭师大信息科学与工程学院却爆红,每学期都遭"秒杀",以前 ...

  5. java程序设计实训项目_Java程序设计教程与项目实训

    本书以现代教育理念为指导,在讲授方式上注意结合应用开发实例,注重培养学生理解面向对象程序设计思想,以提高分析问题和解决实际问题的能力.采用由浅入深.理论与实践相结合的教学思路,通过大量的实例阐述Jav ...

  6. Java 后端开发实践 - 项目模板(16 步)

    在我的工作中,我从零开始搭建了不少软件项目,其中包含了基础代码框架和持续集成基础设施等,这些内容在敏捷开发中通常被称为"第0个迭代"要做的事情.但是,当项目运行了一段时间之后再来反 ...

  7. 20155307 2016-2017第二次《Java程序设计》课堂实践项目

    一.String类的使用 模拟实现Linux下Sort -t -k 2的功能.参考 Sort的实现. 在java.lang包中有String.split()方法,它可以把字符串分割为好几个小的字符串. ...

  8. C++程序设计-第九周分支结构程序设计上机实践项目

    回到课程主页,链接:C++程序设计课程主页-2012级 本次上机对应的教学内容:第3章   C++程序设计初步中分支程序设计的部分. 练习+上机验证 [练习1]阅读下列程序,在准备期写出程序的运行结果 ...

  9. Java IO流实践项目

    一.项目需求 据了解,目前在校大学生80%以上有做兼职的需求,兼职打工已经不仅仅是经济困难的学生赚取生活费用的途径.调查显示,全球经济危机对就业产生冲击,用人单位对人员的社会实践能力要求提高,大学期间 ...

  10. 《C语言及程序设计》实践项目——穷举法解题

    返回:贺老师课程教学链接 说明:穷举法在有些时候,并不是一种最有效率的解决方案,但却是最直观的.初学者依靠这一组问题的解决,将获得程序设计的最直接体验,以及会想问题的头脑. [项目1-小明借书] 小明 ...

最新文章

  1. 一线大厂在机器学习方向的面试题(一)
  2. 计算机应用基础中专教材pdf,中等职业教育通用教材-计算机应用基础.pdf
  3. 如何在移动端复制到剪切板
  4. 最全的 netcore 3.0 升级实战方案
  5. 修改linux远程主机名命令hostname
  6. Android 系统(33)---sensor移植总结
  7. javax.net.ssl.SSLException: java.lang.RuntimeException: Could not generate DH keypair
  8. 四部门联合约谈蚂蚁集团有关人员;苹果11月11日再开发布会;树莓派 400 发布|极客头条
  9. 揭秘计算机之间互发数据的关键原理!
  10. wordpress 伪静态nginx设置
  11. vue 花括号里面的变量_二、Vue条件指令
  12. c语言下楼的题目,用C语言编写下面题目的程序:
  13. mysql 通达信公式_公式选股--均线黏合(更多公式关注公众号“斯达克逻辑”)...
  14. 两款清爽全能的下载神器,还不跟迅雷说拜拜?
  15. 模仿dos窗口下的windows窗口程序
  16. SAP RETAIL 自动补货WRP1R事务代码报错 - Forecast values for determining target stock do not exist -
  17. 文本特征提取——one-hot
  18. JAVA局域网飞鸽传书软件设计与实现免费
  19. 数明SLM27517能驱动MOSFET和IGBT功率开关 低侧栅极驱动器兼容UCC27517
  20. Java数据结构之图

热门文章

  1. 学计算机的大学生买什么U盘,大学生最容易丢的几样东西,最后一件最让人着急,网友:真实了...
  2. python制作中秋贺卡图片_中秋贺卡手工制作图片
  3. cramer定理_线性代数部分重要定理总结
  4. soapui返回值类型都有哪些_小程序都有哪些类型,开发小程序效果如何
  5. python颜色参数_python matplotlib:plt.scatter() 大小和颜色参数详解
  6. ES6之导入模块时的内存共享
  7. hibernate 入门案例
  8. java volatile 和Transient 关键字
  9. linux 修改默认语言
  10. Lync Server 2010迁移至Lync Server 2013部署系列 Part14:A/V服务器目录迁移