[toc] 一.題目要求 我們在剛開始上課的時候介紹過一個小學四則運算自動生成程式的例子,請實現它,要求: 能夠自動生成四則運算練習題 可以定製題目數量 用戶可以選擇運算符 用戶設置最大數(如十以內、百以內等) 用戶選擇是否有括弧、是否有小數 用戶選擇輸出方式(如輸出到文件、印表機等) 最好能提供圖 ...
目錄
一.題目要求
- 我們在剛開始上課的時候介紹過一個小學四則運算自動生成程式的例子,請實現它,要求:
- 能夠自動生成四則運算練習題
- 可以定製題目數量
- 用戶可以選擇運算符
- 用戶設置最大數(如十以內、百以內等)
- 用戶選擇是否有括弧、是否有小數
- 用戶選擇輸出方式(如輸出到文件、印表機等)
- 最好能提供圖形用戶界面(根據自己能力選做,以完成上述功能為主)
二.角色分工
駕駛員:楊浩(本人)
領航員:馮俊鵬 博客地址
三.代碼及代碼地址
題目生成
class BinaryTree
{
private TreeNode root;
private int num;
private ArrayList<TreeNode> opeList = new ArrayList<TreeNode>();
public BinaryTree(int num){
this.num=num;
}
public int getNum(){
return num;
}
public void setNum(int num){
this.num = num;
}
public void setTreeNode(TreeNode root){
this.root = root;
}
/**
* 獲取最終的表達式,必須在CalAndVal()方法後調用
*
* @return str
*/
public String toString(){
String str = root.toString();
str = str.substring(1, str.length()-1);
return str;
}
/**
* 計算並驗證表達式
*
* @return result
*/
public String CalAndVal(){
return root.getResult();
}
/**
* 計算二叉樹的深度(層數)
*
* @return deep
*/
public int getDeep(){
int i = this.num;
int deep = 2;
while(i/2 > 0){
deep++;
i /= 2;
}
return deep;
}
/**
* 生成二叉樹
*
*/
public void createBTree(){
TreeNode lchild, rchild, lnode, rnode;
if(num == 1){
lchild = new TreeNode(String.valueOf(Ran.getNumber(10)), null, null);
rchild = new TreeNode(String.valueOf(Ran.getNumber(10)), null, null);
root = new TreeNode(String.valueOf(Ran.getOperator()), lchild, rchild);
}
else{
int num1 = 0;
int n = getDeep() - 3;
boolean[] place = Ran.getChildPlace(num);
root = new TreeNode(String.valueOf(Ran.getOperator()), null, null);
opeList.add(root);
for(int i = 0; i < n; i++){
for(int j = 0; j < (int)Math.pow(2, i); j++, num1++){
lchild = new TreeNode(String.valueOf(Ran.getOperator()), null, null);
rchild = new TreeNode(String.valueOf(Ran.getOperator()), null, null);
opeList.get(j + num1).setChild(lchild, rchild); //?
opeList.add(lchild);
opeList.add(rchild);
}
}
for(int i = 0; i < place.length; i++){
if(place[i]){
lnode = new TreeNode(String.valueOf(Ran.getNumber(10)), null, null);
rnode = new TreeNode(String.valueOf(Ran.getNumber(10)), null, null);
if(i%2 == 0){
lchild = new TreeNode(String.valueOf(Ran.getOperator()), lnode, rnode);
opeList.add(lchild);
opeList.get(num1).setLchild(lchild);
}
else{
rchild = new TreeNode(String.valueOf(Ran.getOperator()), lnode, rnode);
opeList.add(rchild);
opeList.get(num1).setRchild(rchild);
}
}
else{
if(i%2 == 0){
lchild = new TreeNode(String.valueOf(Ran.getNumber(10)), null, null);
opeList.get(num1).setLchild(lchild);
}
else{
rchild = new TreeNode(String.valueOf(Ran.getNumber(10)), null, null);
opeList.get(num1).setRchild(rchild);
}
}
num1 = num1 + i%2;
}
}
}
}
class Ran {
/**
* 獲取隨機的符號
*
* @return operator
*/
public static char getOperator(){
char operator = 0;
Random ran = new Random();
int i = ran.nextInt(4);
switch(i){
case 0:
operator = '+';
break;
case 1:
operator = '-';
break;
case 2:
operator = '*';
break;
case 3:
operator = '/';
break;
}
return operator;
}
/**
* 根據輸入的範圍獲取隨機數
*
* @param max
* @return number
*/
public static int getNumber(int max){
int number = 0;
max=test.maxNum;
Random ran = new Random();
number = ran.nextInt(max+1);
return number;
}
/**
* 根據運算符的個數隨機產生子節點的位置
*
* @param num
* @return childPlace
*/
public static boolean[] getChildPlace(int num){
int d = 0;
int size = 0, j=1;
while(num >= (int)Math.pow(2, j)){
j++;
}
d = (int)Math.pow(2, j) - 1 - num;
size = (int)Math.pow(2, j-1);
boolean[] k = new boolean[size];
for(int i = 0; i < size; i++){
k[i] = true;
}
for(int i = 0; i < d; i++){
Random ran = new Random();
int f = ran.nextInt(size);
while(k[f] == false)
{
f = ran.nextInt(size);
}
k[f] = false;
}
return k;
}
}
class TreeNode {
private String str;
private TreeNode rchild = null;
private TreeNode lchild = null;
public TreeNode(String str){
this.str = str;
}
public TreeNode(String str, TreeNode lchild, TreeNode rchild){
this.str = str;
this.rchild = rchild;
this.lchild = lchild;
}
public void setChild(TreeNode lchild, TreeNode rchild){
this.lchild = lchild;
this.rchild = rchild;
}
public TreeNode getRchild() {
return rchild;
}
public void setRchild(TreeNode rchild) {
this.rchild = rchild;
}
public TreeNode getLchild() {
return lchild;
}
public void setLchild(TreeNode lchild) {
this.lchild = lchild;
}
public String getStr(){
return str;
}
/**
* 獲取每個節點的運算結果,並檢驗除法
* 1)除數為0
* 2)不能整除
* 出現以上兩種情況的話將該運算符轉換成其他三種運算符
*
* @return result
*/
public String getResult(){
if(hasChild()){
switch(str){
case "+":
return String.valueOf(Integer.parseInt(getLchild().getResult()) + Integer.parseInt(getRchild().getResult()));
case "-":
return String.valueOf(Integer.parseInt(getLchild().getResult()) - Integer.parseInt(getRchild().getResult()));
case "*":
return String.valueOf(Integer.parseInt(getLchild().getResult()) * Integer.parseInt(getRchild().getResult()));
case "/":
if(getRchild().getResult().equals("0")){
while(str.equals("/")){
str = String.valueOf(Ran.getOperator());
}
return this.getResult();
}
else if(Integer.parseInt(getLchild().getResult()) % Integer.parseInt(getRchild().getResult()) != 0){
while(str.equals("/")){
str = String.valueOf(Ran.getOperator());
}
return this.getResult();
}
else
return String.valueOf(Integer.parseInt(getLchild().getResult()) / Integer.parseInt(getRchild().getResult()));
}
}
return str;
}
/**
* 先對每個運算式添加括弧,然後根據去括弧法則,去掉多餘的子式的括弧
*
* @return string
*/
public String toString(){
String Lstr = "", Rstr = "", Str = "";
if(hasChild()){
//右子樹如果有孩子,說明右子樹是一個表達式,而不是數位元組點。
if(getRchild().hasChild()){
//判斷左鄰括弧的運算符是否為'/'
if(str.equals("/")){
//獲取右子樹的表達式,保留括弧
Rstr = getRchild().toString();
}
//判斷左鄰括弧的運算符是否為'*'或'-'
else if(str.equals("*") || str.equals("-")){
//判斷op是否為'+'或'-'
if(getRchild().str.equals("+") || getRchild().str.equals("-")){
Rstr = getRchild().toString();
}
else{
//獲取右子樹的表達式,並且去括弧
Rstr = getRchild().toString().substring(1, getRchild().toString().length()-1);
}
}
else{
//右子樹除此之外都是可以去括弧的。
Rstr = getRchild().toString().substring(1, getRchild().toString().length()-1);
}
}
else{
Rstr = getRchild().str;
}
//左子樹的情況同右子樹類似
if(getLchild().hasChild()){
if(str.equals("*") || str.equals("/")){
if(getLchild().str.equals("+") || getLchild().str.equals("-")){
Lstr = getLchild().toString();
}
else{
Lstr = getLchild().toString().substring(1, getLchild().toString().length()-1);
}
}
else{
Lstr = getLchild().toString().substring(1, getLchild().toString().length()-1);
}
}
else{
Lstr = getLchild().str;
}
//獲取當前的運算式,並加上括弧
Str = "(" + Lstr + str + Rstr + ")";
}
else{
//若沒有孩子,說明是數位元組點,直接返回數字
Str = str;
}
return Str;
}
public boolean hasChild(){
if(lchild == null && rchild == null)
return false;
else
return true;
}
}
圖形界面生成及輸出
public static void InitUI()
{
JFrame frame =new JFrame();
frame.setTitle("四則運算");
frame.setSize(500, 500);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(3);
FlowLayout f1=new FlowLayout(FlowLayout.LEFT);
frame.setLayout(f1);
JLabel name1=new JLabel("請輸入題目個數:");
frame.add(name1);
JTextField name1text=new JTextField();//文本框
name1text.setPreferredSize(new Dimension(50, 30));
frame.add(name1text);
JLabel name=new JLabel();//空
name.setPreferredSize(new Dimension(110,30));
frame.add(name);
JLabel name2=new JLabel("請輸入最大值:");
frame.add(name2);
JTextField name2text=new JTextField();//文本框
name2text.setPreferredSize(new Dimension(50, 30));
frame.add(name2text);
JLabel name4=new JLabel("是否輸出到文件:");
frame.add(name4);
JRadioButton jrb1, jrb2;
jrb1 = new JRadioButton("是");
jrb2 = new JRadioButton("否");
frame.add(jrb1);
frame.add(jrb2);
JLabel name5=new JLabel();//空
name5.setPreferredSize(new Dimension(110,30));
frame.add(name5);
JButton bu=new JButton("生成");
bu.setPreferredSize(new Dimension(80,30));
frame.add(bu);
JLabel name3=new JLabel();//空
name3.setPreferredSize(new Dimension(50,30));
frame.add(name3);
JLabel name7=new JLabel("題目:");
frame.add(name7);
JLabel name6=new JLabel();//空
name6.setPreferredSize(new Dimension(250,30));
frame.add(name6);
JTextField Titletext=new JTextField();//文本框
Titletext.setPreferredSize(new Dimension(450, 300));
frame.add(Titletext);
/**
* 事件監聽器
*/
bu.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
String a=name1text.getText();
int Title_Num = Integer.parseInt(a); //string轉換為int
String b=name2text.getText();
maxNum = Integer.parseInt(b); //string轉換為int
String[] Title=new String[Title_Num];
String[] result1=new String[Title_Num];
for(int i = 0; i < Title_Num; i++){
BinaryTree bTree;
bTree = new BinaryTree(2);
bTree.createBTree();
String result = bTree.CalAndVal();
Title[i]=bTree.toString();
result1[i]=result;
System.out.println(Title[i]+"="+result1[i]);
}
Titletext.setText(getStringByArray(Title,result1));
/**
* 文件輸出
*/
if(jrb1.isSelected()) {
try{
PrintStream mytxt=new PrintStream("./test.txt");
PrintStream out=System.out;
System.setOut(mytxt);
for(int i = 0; i < Title_Num; i++){
System.out.println(Title[i] + "=" + result1[i]);
}
System.setOut(out);
}catch(FileNotFoundException e1){
e1.printStackTrace();
}
}
}
});
frame.setVisible(true);
}
/**
*
* @將題目整和成一個字元串,方便setText輸出
* @param b
* @return str
*/
public static String getStringByArray(String[] a,String[] b) {
String str = "";
for(int i=0;i<a.length;i++) {
str += a[i];
str += '=';
str += b[i];
str += ' ';
str += ' ';
str += ' ';
str += ' ';
}
return str;
}
四.運行結果截圖
圖形框架截圖
輸出到文本框
輸出到文件
五.參考資料
隨機生成四則運算式及答案(含括弧)
如何將java的輸出保存到文件中作為程式日誌
Java實現圖形界面
Java 圖形化界面設計(GUI)實戰練習(代碼)
Java如何畫圖形用戶界面
java按鈕的監聽事件
java圖形界面中怎麼用settext輸出一個數組
六.工作照片
七.評價及總結
在這次的作業中,我的領航員是馮俊鵬同學,他在過程中給了我很大的幫助,不斷地督促我儘快完成,遇到不會的問題和我一起解決,是使我的代碼更加完善,沒有他的話我很難完成這次的作業。
通過這次作業,我完成了我的第一個擁有圖形界面的作品,在這之前一直都是用黑框進行操作,編寫代碼的過程是非常困難的,有許許多多的問題根本不知道如何解決,例如圖形化界面的實現、界面的輸入和輸出和事件監聽器的編寫等等,碰到這些問題只能去網上搜索 ,找了很多的參考文章,上面列舉出的僅僅只是其中一小部分,程式實現了一部分功能,但還有幾個功能沒有實現,例如選擇小數和選擇括弧,圖形界面的編寫也比較混亂,但是,在這次的代碼編寫過程中,我學到了很多以前根本不會的知識,收穫了很多。