20155227 《Java程序设计》实验五 Java网络编程及安全实验报告
实验内容
任务一:
- 编写MyBC.java实现中缀表达式转后缀表达式的功能。
- 编写MyDC.java实现从上面功能中获取的表达式中实现后缀表达式求值的功能。
我们如何编程实现bc
? 把中缀式转化后缀式调用MyDC.java
中的evaluate
方法就行了。这样问题转化为如何由中缀式求得后缀式?
由中缀式
求得后缀式
可以使用栈,伪代码如下:
设立一个栈,存放运算符,首先栈为空;
从左到右扫描中缀式,若遇到操作数,直接输出,并输出一个空格作为两个操作数的分隔符;
若遇到运算符,则与栈顶比较,比栈顶级别高则进栈,否则退出栈顶元素并输出,然后输出一个空格作分隔符;
若遇到左括号,进栈;若遇到右括号,则一直退栈输出,直到退到左括号止。
当栈变成空时,输出的结果即为后缀表达式。
MyBC:
import java.util.*;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.Arrays;
public class MyBC {
private static LinkedList<String> op1 = new LinkedList<>();
private static LinkedList<String> op2 = new LinkedList<>();
private static StringBuilder a = new StringBuilder();
public StringBuilder houzhui(LinkedList<String> list) {
Iterator<String> i = list.iterator();
while (i.hasNext()) {
String s = i.next();
if (isOperator(s)) {
if (op1.isEmpty()) {
op1.push(s);
} else {
if (priority(op1.peek()) <= priority(s) && !s.equals(")")) {
op1.push(s);
} else if (!s.equals(")") && priority(op1.peek()) > priority(s)) {
while (op1.size() != 0 && priority(op1.peek()) >= priority(s)
&& !op1.peek().equals("(")) {
if (!op1.peek().equals("(")) {
String operator = op1.pop();
a.append(operator).append(" ");
op2.push(operator);
}
}
op1.push(s);
} else if (s.equals(")")) {
while (!op1.peek().equals("(")) {
String operator = op1.pop();
a.append(operator).append(" ");
op2.push(operator);
}
op1.pop();
}
}
} else {
a.append(s).append(" ");
op2.push(s);
}
}
if (!op1.isEmpty()) {
Iterator<String> iterator = op1.iterator();
while (iterator.hasNext()) {
String operator = iterator.next();
a.append(operator).append(" ");
op2.push(operator);
iterator.remove();
}
}
return a;
}
private static boolean isOperator(String oper) {
if (oper.equals("+") || oper.equals("-") || oper.equals("/") || oper.equals("*")
|| oper.equals("(") || oper.equals(")")) {
return true;
}
return false;
}
private static int priority(String s) {
switch (s) {
case "+":
return 1;
case "-":
return 1;
case "*":
return 2;
case "/":
return 2;
case "(":
return 3;
case ")":
return 3;
default:
return 0;
}
}
}
我们如何实现dc
?
这要用到栈。对逆波兰式求值时,不需要再考虑运算符的优先级,只需从左到右扫描一遍后缀表达式即可。求值伪代码如下:
设置一个操作数栈,开始栈为空;
从左到右扫描后缀表达式,遇操作数,进栈;
若遇运算符,则从栈中退出两个元素,先退出的放到运算符的右边,后退出的放到运算符左边,运算后的结果再进栈,直到后缀表达式扫描完毕。
此时,栈中仅有一个元素,即为运算的结果。
MyDC:
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.*;
public class MyDC {
public static int evaluate(StringBuilder b) {
LinkedList<String> mList = new LinkedList<>();
String[] postStr = b.toString().split(" ");
int result;
for (String s : postStr) {
if (fuhao(s)) {
if (!mList.isEmpty()) {
int num1 = Integer.valueOf(mList.pop());
int num2 = Integer.valueOf(mList.pop());
if (s.equals("/") && num1 == 0) {
System.out.println("除数不能为0");
return 0;
}
int newNum = cal(num2, num1, s);
mList.push(String.valueOf(newNum));
}
} else {
mList.push(s);
}
}
//if (!mList.isEmpty()) {
//System.out.println("result: "+mList.pop());
result=Integer.parseInt(mList.pop());
// }
return result;
}
private static boolean fuhao(String a) {
if (a.equals("+") || a.equals("-") || a.equals("/") || a.equals("*")
|| a.equals("(") || a.equals(")")) {
return true;
}
return false;
}
/*private static int priority(String s) {
switch (s) {
case "+":
return 1;
case "-":
return 1;
case "*":
return 2;
case "/":
return 2;
case "(":
return 3;
case ")":
return 3;
default:
return 0;
}
}*/
private static int cal(int num1, int num2, String operator) {
switch (operator) {
case "+":
return num1 + num2;
case "-":
return num1 - num2;
case "*":
return num1 * num2;
case "/":
return num1 / num2;
default:
return 0;
}
}
}
/*private boolean isOperator(String token) {
return (token.equals("+") || token.equals("-") ||
token.equals("*") || token.equals("/"));
}
private int evalSingleOp(char operation, int op1, int op2) {
int result = 0;
switch (operation) {
case ADD:
result = op1 + op2;
break;
case SUBTRACT:
result = op1 - op2;
break;
case MULTIPLY:
result = op1 * op2;
break;
case DIVIDE:
result = op1 / op2;
}
return result;
}
}*/
Test:
import java.util.LinkedList;
import java.util.*;
public class Test {
public static void main(String[] args){
LinkedList<String> list=new LinkedList<>();
StringBuilder result1;
int result2;
String expression, again;
System.out.println("请输入一个中缀表达式并以#结束");
Scanner scanner=new Scanner(System.in);
String s;
while (!(s=scanner.next()).equals("#")) {
list.add(s);
}
MyBC hz=new MyBC();
result1 = hz.houzhui(list);
System.out.println("后缀表达式: "+result1);
MyDC evaluator = new MyDC();
result2 = evaluator.evaluate(result1);
System.out.println("That expression equals " + result2);
System.out.println();
}
}
任务二
- 结对编程:一人负责客户端,另一人负责服务器
- 注意责任归宿,要会通过测试证明自己没有问题
- 基于Java Socket实现客户端/服务器功能,传输方式用TCP
- 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式通过网络发送给服务器
- 服务器接收到后缀表达式,调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
- 客户端显示服务器发送过来的结果
我负责的是服务器部分
任务三
- 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密后通过网络把密文发送给服务器
- 服务器接收到后缀表达式表达式后,进行解密(和客户端协商密钥,可以用数组保存),然后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
- 其他要求同任务二
任务四
- 客户端和服务器用DH算法进行3DES或AES算法的密钥交换
- 其他要求同任务三
任务五
- 服务器接收到后缀表达式表达式后,进行解密,解密后计算明文的MD5值,和客户端传来的MD5进行比较,一致则调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
- 其他要求同任务四
PSP(Personal Software Process)时间
需求分析 | 20min | 12.5% |
设计 | 20min | 12.5% |
代码实现 | 80min | 50% |
测试 | 20min | 12.5% |
分析总结 | 20min | 12.5% |