项目一:迷宫求解 a)需求分析: 要求 可以输入一个任意大小的迷宫数据,用非递归的方法求出一条走出迷宫的路径,并将路径输出
b)概要设计: 思路
我打算设计一个迷宫游戏,用不同的算法生成迷宫,再用不同算法作路径规划
非递归的方法排除dfs路径规划方法
制作成可视化的程序
实现BFS算法寻找迷宫终点
实现基本的地图及寻找路径可视化
实现prim迷宫生成算法
改进BFS算法
独立出地图绘制类,供不同算法使用
封装主地图类
封装节点类
启用Scene Builder工具编写界面-
实现基本的UI界面
封装所有页面,改写为ButtonChose类的方法,实现页面跳转
加入DFS迷宫生成算法
重构MainMap类及其子类
重构bfs寻路算法
加入AStar寻路算法
加入bfs寻路算法
项目整体的设置思路图
一些数据结构设计图
设计说明: 该项目被我设计了一个迷宫游戏,玩家可以通过选择界面对迷宫的大小尺寸,迷宫的生成方式,起点与终点,屏幕分辨率等等属性进行时设置
点击开始游戏后,游戏会根据玩家的设置根据相应算法生成迷宫,玩家可以通过aswd四个键位操作角色走迷宫。
玩家可以通过按键J来使用BFS算法实时实现路径规划(显示角色到终点的路径,实时运算)
玩家可以通过按键L来使用AStar算法实时实现路径规划(显示角色到终点的路径,实时运算)
玩家可以通过按键K来进行角色导航(显示角色到终点的行走动画,实时运算,默认BFS算法)
算法的设计有:
随机prim迷宫生成算法
随机dfs迷宫生成算法
AStar路径规划算法
BFS路径规划算法
用到的数据结构有:
链表
队列
双端队列
栈
优先队列
广义表
数组
树
c)详细设计: 地图的每个点—Node类的设计 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 class Node { int FValue; int HValue; int GValue; int x, y; int pre; int id = 0 ; boolean isVisited=false ; int value=1 ; public Node () { } public Node (int x, int y, int pre) { this .x = x; this .y = y; this .pre = pre; } public Node (int x, int y) { this .x = x; this .y = y; } public int getX () { return x; } public void setX (int x) { this .x = x; } public int getY () { return y; } public void setY (int y) { this .y = y; } public int getPre () { return pre; } public void setPre (int pre) { this .pre = pre; } public void setId (int id) { this .id = id; } public int getId () { return id; } public boolean isVisited () { return isVisited; } public void setVisited (boolean visited) { isVisited = visited; } public int getValue () { return value; } public void setValue (int value) { this .value = value; } public void setHValue (Node end) { HValue= Math.abs(x-end.getX())+Math.abs(y- end.getY()); } public void setGValue (Node start) { HValue= Math.abs(x-start.getX())+Math.abs(y- start.getY()); } public int getFValue () { FValue=HValue+GValue; return FValue; } @Override public String toString () { return new String (x+" " +y); } }
迷宫生成算法接口的设计 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 public class MainMap { protected Node start; protected Node end; protected int col; protected int row; protected Node nodeMap[][]; public int getCol () { return col; } public void setCol (int col) { this .col = col; } public int getRow () { return row; } public void setRow (int row) { this .row = row; } public MainMap (int col, int row) { this .col = col; this .row = row; nodeMap=new Node [row][col]; } public void InitMap () { for (int i=0 ;i<row;i++){ for (int j=0 ;j< col;j++){ Node temp=new Node (i,j); nodeMap[i][j]=temp; } } start=new Node (((int )(Math.random()*row/2 +1 )),((int )(Math.random()*col/2 +1 ))); end=new Node ((int )((Math.random()*row)/2 +row/2 ),(int )((Math.random()*col))/2 +col/2 ); } public void makeMap () { } public Node getStart () { return start; } public void setStart (Node start) { this .start = start; } public Node getEnd () { return end; } public void setEnd (Node end) { this .end = end; } public void showMap () { System.out.println("起点:" +start.getX()+" " +start.getY()); System.out.println("终点:" +end.getX()+" " +end.getY()); for (int i=0 ;i<row;i++){ for (int j=0 ;j< col;j++){ System.out.print(nodeMap[i][j].value +" " ); } System.out.println(); } } public MainMap clone () { MainMap clone = new MainMap (col,row); clone.InitMap(); for (int i=0 ;i<row;i++){ for (int j=0 ;j<col;j++){ clone.nodeMap[i][j].setValue(nodeMap[i][j].getValue()); clone.nodeMap[i][j].setPre(nodeMap[i][j].getPre()); clone.nodeMap[i][j].setVisited(nodeMap[i][j].isVisited()); clone.nodeMap[i][j].setX(nodeMap[i][j].getX()); clone.nodeMap[i][j].setY(nodeMap[i][j].getY()); clone.nodeMap[i][j].setId(nodeMap[i][j].getId()); } } clone.end=end; clone.start=start; return clone; } }
地图接口设计 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 public class MainMap { protected Node start; protected Node end; protected int col; protected int row; protected Node nodeMap[][]; public int getCol () { return col; } public void setCol (int col) { this .col = col; } public int getRow () { return row; } public void setRow (int row) { this .row = row; } public MainMap (int col, int row) { this .col = col; this .row = row; nodeMap=new Node [row][col]; } public void InitMap () { for (int i=0 ;i<row;i++){ for (int j=0 ;j< col;j++){ Node temp=new Node (i,j); nodeMap[i][j]=temp; } } start=new Node (((int )(Math.random()*row/2 +1 )),((int )(Math.random()*col/2 +1 ))); end=new Node ((int )((Math.random()*row)/2 +row/2 ),(int )((Math.random()*col))/2 +col/2 ); } public void makeMap () { } public Node getStart () { return start; } public void setStart (Node start) { this .start = start; } public Node getEnd () { return end; } public void setEnd (Node end) { this .end = end; } public void showMap () { System.out.println("起点:" +start.getX()+" " +start.getY()); System.out.println("终点:" +end.getX()+" " +end.getY()); for (int i=0 ;i<row;i++){ for (int j=0 ;j< col;j++){ System.out.print(nodeMap[i][j].value +" " ); } System.out.println(); } } public MainMap clone () { MainMap clone = new MainMap (col,row); clone.InitMap(); for (int i=0 ;i<row;i++){ for (int j=0 ;j<col;j++){ clone.nodeMap[i][j].setValue(nodeMap[i][j].getValue()); clone.nodeMap[i][j].setPre(nodeMap[i][j].getPre()); clone.nodeMap[i][j].setVisited(nodeMap[i][j].isVisited()); clone.nodeMap[i][j].setX(nodeMap[i][j].getX()); clone.nodeMap[i][j].setY(nodeMap[i][j].getY()); clone.nodeMap[i][j].setId(nodeMap[i][j].getId()); } } clone.end=end; clone.start=start; return clone; } }
路径规划算法接口设计 1 2 3 public interface SF { public LinkedList<Node> find3 () ; }
Prim随机生成地图算法原理与代码 1.让迷宫全是墙. 2.选一个单元格作为迷宫的通路,然后把它的邻墙放入列表 3.当列表里还有墙时 1.从列表里随机选一个墙,如果这面墙分隔的两个单元格只有一个单元格被访问过 1.那就从列表里移除这面墙,即把墙打通,让未访问的单元格成为迷宫的通路 2.把这个格子的墙加入列表 2.如果墙两面的单元格都已经被访问过,那就从列表里移除这面墙
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 public void makeMap () { InitMap(); nodeMap[1 ][1 ].setValue(0 ); LinkedList<Node> listA=new LinkedList <>(); LinkedList<Node> listB= null ; int tempR = 0 ; int tempC = 0 ; Node temp=nodeMap[1 ][3 ]; listA.add(temp); temp=nodeMap[3 ][1 ]; listA.add(temp); while (listA.size()!=0 ){ int randomNodeId=(int )(listA.size()*Math.random()); Node randomA=listA.get(randomNodeId); listB=new LinkedList <>(); boolean flag=true ; for (int i=0 ;i<4 ;i++){ switch (i){ case 0 :tempR=randomA.getX()-2 ;tempC=randomA.getY();break ; case 1 :tempR=randomA.getX()+2 ;tempC=randomA.getY();break ; case 2 :tempR=randomA.getX();tempC=randomA.getY()+2 ;break ; case 3 :tempR=randomA.getX();tempC=randomA.getY()-2 ;break ; } if (!(tempC<col&&tempC>=0 &&tempR>=0 &&tempR<row)){ continue ; } if (nodeMap[tempR][tempC].getValue()==0 ){ temp=nodeMap[tempR][tempC]; listB.add(temp); } else if (nodeMap[tempR][tempC].getValue()==1 &&!listA.contains(nodeMap[tempR][tempC])){ temp=nodeMap[tempR][tempC]; listA.add(temp); } } int randomPass=(int )(listB.size()*Math.random()); Node randomB=listB.get(randomPass); nodeMap[randomA.getX()][randomA.getY()].setValue(0 ); nodeMap[(randomB.getX()+randomA.getX())>>1 ][(randomA.getY()+randomB.getY())>>1 ].setValue(0 ); listA.remove(randomA); } while (nodeMap[end.getX()][end.getY()].getValue()==1 ){ end=new Node ((int )((Math.random()*row)/2 +row/2 ),(int )((Math.random()*col))/2 +col/2 ); } }
DFS随机生成地图算法原理与代码 1.将起点作为当前迷宫单元并标记为已访问 2.当还存在未标记的迷宫单元,进行循环 1.如果当前迷宫单元有未被访问过的的相邻的迷宫单元 1.随机选择一个未访问的相邻迷宫单元 2.将当前迷宫单元入栈 3.移除当前迷宫单元与相邻迷宫单元的墙 4.标记相邻迷宫单元并用它作为当前迷宫单元 2.如果当前迷宫单元不存在未访问的相邻迷宫单元,并且栈不空 1.栈顶的迷宫单元出栈 2.令其成为当前迷宫单元
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 public void makeMap () { InitMap(); LinkedList<Node> stackList=new LinkedList <>(); Node current=nodeMap[1 ][1 ]; nodeMap[1 ][1 ].setVisited(true ); stackList.add(current); while (stackList.size()!=0 ) { int tempR=0 ; int tempC=0 ; LinkedList<Node> AdjList=new LinkedList <>(); for (int i=0 ;i<4 ;i++){ switch (i){ case 0 :tempR=current.getX()-2 ;tempC=current.getY();break ; case 1 :tempR=current.getX()+2 ;tempC=current.getY();break ; case 2 :tempR=current.getX();tempC=current.getY()+2 ;break ; case 3 :tempR=current.getX();tempC=current.getY()-2 ;break ; } if (!(tempC<col&&tempC>0 &&tempR>0 &&tempR<row)){ continue ; } if (nodeMap[tempR][tempC].isVisited==false ){ AdjList.add(nodeMap[tempR][tempC]); } } if (AdjList.size()!=0 ) { int randomDir = (int ) ((AdjList.size() * Math.random())); Node adjNode = AdjList.get(randomDir); stackList.push(current); adjNode.setValue(0 ); current.setValue(0 ); nodeMap[(adjNode.getX()+current.getX())>>1 ][(adjNode.getY()+current.getY())>>1 ].setValue(0 ); nodeMap[(adjNode.getX()+current.getX())>>1 ][(adjNode.getY()+current.getY())>>1 ].setVisited(true ); adjNode.setVisited(true ); current=adjNode; } if (stackList.size()!=0 &&AdjList.size()==0 ) { current=stackList.pop(); } } while (nodeMap[end.getX()][end.getY()].getValue()==1 ){ end=new Node ((int )((Math.random()*row)/2 +row/2 ),(int )((Math.random()*col))/2 +col/2 ); } }
BFS路径规划算法原理及代码 从迷宫的入口开始,进行层次优先遍历(BFS,我更喜欢称之为层次优先遍历,因为这样更形象)。BFS遍历的关键就是需要用到一个队列,在这道题中,只需要从入口点出发,依次看下它的上下左右四个结点是否可以走,如果可以走,就立即把这个结点push到队列尾部,然后每次找的时候就是从队头取出一个点,依次看它的上下左右四个方向。遍历的路径的时候注意是从出口往入口找,所以需要用到一个栈保存一下路径。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 public boolean find () { Node start= mainMap.getStart(); Node end=mainMap.getEnd(); start.setPre(-1 ); nodeMap =mainMap.nodeMap; linkedList=new LinkedList <>(); Node temp=null ; linkedList.offer(start); rear++; nodeMap[start.getX()][start.getY()].setValue(-1 ); while (!(front==rear)) { temp=linkedList.get(++front); if (temp.getX() ==end.getX() && temp.getY() ==end.getY()) { return true ; } Node temp2 = null ; for (int i = 0 ; i < 4 ; i++) { switch (i) { case 0 : temp2 = new Node (temp.x, temp.y - 1 ); break ; case 1 : temp2 = new Node (temp.x, temp.y + 1 ); break ; case 2 : temp2 = new Node (temp.x - 1 , temp.y); break ; case 3 : temp2 = new Node (temp.x + 1 , temp.y); break ; } if (temp2.getX()<mainMap.getCol()&&temp2.getX()>0 &&temp.getY()>0 &&temp2.getY()<mainMap.getRow()&&nodeMap[temp2.getX()][temp2.getY()].getValue()==0 ) { linkedList.offer(temp2); rear++; temp2.id=linkedList.indexOf(temp2); temp2.setPre(temp.getId()); nodeMap[temp2.getX()][temp2.getY()].setValue(-1 ); } } } return false ; } public boolean find2 () { linkedList2=new LinkedList <>(); linkedList2.add(linkedList.get(front)); int j=0 ; while (linkedList2.get(j).getPre()!=-1 ){ linkedList2.add(linkedList.get(linkedList2.get(j).getPre())); j++; } linkedList=linkedList2; return true ; } public LinkedList<Node> find3 () { long time1=new Date ().getTime(); System.out.println(time1); find(); find2(); long time2=new Date ().getTime(); System.out.println(time2); System.out.println(time2-time1); return linkedList; }
AStar路径规划算法原理及代码
1.起点先添加到开启列表中 2.开启列表中有节点的话,取出第一个节点,即最小F值的节点 判断此节点是否是目标点,是则找到了,跳出 根据此节点取得四个方向的节点,求出G,H,F值 判断每个节点在地图中是否能通过,不能通过则加入关闭列表中,跳出 判断每个节点是否在关闭列表中,在则跳出 判断每个节点是否在开启列表中,在则更新G值,F值,还更新其父节点;不在则将其添加到开启列表中,计算G值,H值,F值,添加其节点 3.把此节点从开启列表中删除,再添加到关闭列表中 4.把开启列表中按照F值最小的节点进行排序,最小的F值在第一个 5.重复2,3,4步骤
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 public void find () { open=new PriorityQueue <>(NodeComparator); keptList=new LinkedList <>(); start=mainMap.getStart(); start.setPre(-1 ); nodeMap[start.getX()][start.getY()].setValue(-1 ); start.setGValue(start); start.setHValue(end); open.add(start); while (open.size()!=0 ){ Node current=open.poll(); keptList.offer(current); current.id=keptList.indexOf(current); if (current.getX()==end.getX()&¤t.getY()==end.getY()) {break ;} Node temp2 = null ; for (int i = 0 ; i < 4 ; i++) { switch (i) { case 0 : temp2 = new Node (current.x, current.y - 1 ); break ; case 1 : temp2 = new Node (current.x, current.y + 1 ); break ; case 2 : temp2 = new Node (current.x - 1 , current.y); break ; case 3 : temp2 = new Node (current.x + 1 , current.y); break ; } if (temp2.getX()<mainMap.getCol()&&temp2.getX()>0 &&temp2.getY()>0 &&temp2.getY()<mainMap.getRow()&&nodeMap[temp2.getX()][temp2.getY()].getValue()==0 ) { temp2.setGValue(start); temp2.setHValue(end); temp2.setPre(current.getId()); nodeMap[temp2.getX()][temp2.getY()].setValue(-1 ); open.add(temp2); } } } } public boolean find2 () { LinkedList<Node>linkedList2=new LinkedList <>(); linkedList2.add(keptList.getLast()); int j=0 ; while (linkedList2.get(j).getPre()!=-1 ){ linkedList2.add(keptList.get(linkedList2.get(j).getPre())); j++; } keptList=linkedList2; return true ; } public LinkedList<Node> find3 () { long time1=new Date ().getTime(); System.out.println(time1); find(); find2(); long time2=new Date ().getTime(); System.out.println(time2); System.out.println(time2-time1); return keptList; }
绘图接口设计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package com.gallifrey.mazegame4;import javafx.scene.Group;public class MainPrint { protected Group group; protected MainMap mainMap; protected double OneCol; protected double OneRow; public MainPrint (Group group,MainMap mainMap) { this .group = group; this .mainMap = mainMap; OneCol=(double ) 800 / mainMap.getCol(); OneRow=(double ) 800 /mainMap.getRow(); } }
d)调试分析 开始界面(选择界面)
Prim算法随机生成41*41迷宫
DFS算法随机生成41*41迷宫
路径规划(解迷宫)
角色导航
时间复杂度 prim迷宫生成算法:原:O(n²),使用优先队列改进:O(mlogn)
DFS迷宫生成算法:O(n²)
BFS路径规划算法:O(n²)
AStar路径规划算法:O(m*n);m,n分别是地图的行数和列数
项目二:手写计算器 a)需求分析: 要求 利用计算器实现一元多项式计算,表达式求值是实现程序设计语言的基本问题之一,栈的应用。设计一个程序,演示用算符优先法对算术表达式求值的过程。
该计算器可以进行加减乘除,求余,阶乘,次方根的一元多项式计算
b)概要设计: 思路
利用栈将输入的算术式(中缀表达式)转逆波兰式(后缀表达式)
利用逆波兰式借助栈进行运算
实现基本的可视化以及用户交互功能
整体设计思路图
存储结构的设计
c)详细设计: 栈设计 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 public class MyStack <E> { private int MaxSize=1010 ; private E data[]; private int top=-1 ; public MyStack () { data=(E[])new Object [MaxSize]; } public boolean isEmpty () { return (top==-1 ); } public void push (E e) { if (top==MaxSize-1 ){ System.out.println("栈满了" ); return ; } data[++top]=e; } public E pop () { if (top==-1 ){ System.out.println("栈空" ); return null ; } return data[top--]; } public E getTop () { if (top==-1 ){ System.out.println("栈空" ); return null ; } return data[top]; } }
逆波兰式算法的实现 将一个普通的中缀表达式转换为逆波兰表达式 的一般算法是:
首先需要分配2个栈,一个作为临时存储运算符的栈S1(含一个结束符号),一个作为存放结果(逆波兰式)的栈S2(空栈),S1栈可先放入优先级最低的运算符#,注意,中缀式应以此最低优先级的运算符结束。可指定其他字符,不一定非#不可。从中缀式的左端开始取字符,逐序进行如下步骤:
(1)若取出的字符是操作数,则分析出完整的运算数,该操作数直接送入S2栈。
(2)若取出的字符是运算符,则将该运算符与S1栈栈顶元素比较,如果该运算符(不包括括号运算符)优先级高于S1栈栈顶运算符(包括左括号)优先级,则将该运算符进S1栈(或者栈空),否则,将S1栈的栈顶运算符弹出,送入S2栈中,直至S1栈栈顶运算符(包括左括号)低于(不包括等于)该运算符优先级时停止弹出运算符,最后将该运算符送入S1栈。
(3)若取出的字符是“(”,则直接送入S1栈顶。
(4)若取出的字符是“)”,则将距离S1栈栈顶最近的“(”之间的运算符,逐个出栈,依次送入S2栈,此时抛弃“(”。
(5)重复上面的1~4步,直至处理完所有的输入字符。
(6)若取出的字符是“#”,则将S1栈内所有运算符(不包括“#”),逐个出栈,依次送入S2栈。
计算方法的实现 新建一个表达式,如果当前字符为变量或者为数字,则压栈,如果是运算符,则将栈顶两个元素弹出作相应运算,结果再入栈,最后当表达式扫描完后,栈里的就是结果。
计算器代码的设计:逆波兰式+计算方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 public class Calculator { int State; MyStack <Character>tempStack; MyStack <Character>outStack2; MyStack <String> coutStack; String stringArr[]; int j; String suffix; public Calculator () { tempStack=new MyStack <>(); outStack2=new MyStack <>(); coutStack=new MyStack <>(); suffix=new String (); stringArr=new String [25 ]; } public int getState (char c) { if (c == '+' || c == '-' ) { return 1 ; } else if (c == '*' || c == '/' ) { return 2 ; } else if (c == '%' || c == '^' ) { return 3 ; } else if (c == '!' ) { return 4 ; } else { return 0 ; } } public void getSuffix (char [] input) { int i=0 ; while (input[i]!='\0' ) { if (input[i]>='0' &&input[i]<='9' ){ outStack2.push(input[i++]); } else if (input[i]=='+' ||input[i]=='-' ||input[i]=='*' ||input[i]=='/' ||input[i]=='!' ||input[i]=='%' ||input[i]=='^' ){ if (tempStack.isEmpty()||tempStack.getTop()=='(' ||getState(input[i])>getState(tempStack.getTop())){ tempStack.push(input[i++]); }else { while (!tempStack.isEmpty()&&getState(input[i])<getState(tempStack.getTop())){ outStack2.push(tempStack.pop()); } outStack2.push(tempStack.pop()); } } if (input[i]=='(' ){ tempStack.push(input[i]); } if (input[i]==')' ){ while (tempStack.getTop()!='(' ){ outStack2.push(tempStack.pop()); } tempStack.pop(); } } while (!tempStack.isEmpty()){ outStack2.push(tempStack.pop()); } } public String getSuffix (String input) { suffix=new String (); for (int i=0 ;i<input.length();i++){ if (input.charAt(i)>='0' &&input.charAt(i)<='9' ||input.charAt(i)=='.' ){ suffix += input.charAt(i); String temp=new String (); temp += input.charAt(i); while (i+1 <input.length()&&input.charAt(i+1 )>='0' &&input.charAt(i+1 )<='9' ||i+1 <input.length()&&input.charAt(i+1 )=='.' ) { suffix += input.charAt(i+1 ); temp += input.charAt(i+1 ); i++; } stringArr[j++]=temp; } else if (input.charAt(i)=='+' ||input.charAt(i)=='-' ||input.charAt(i)=='*' ||input.charAt(i)=='/' ||input.charAt(i)=='!' ||input.charAt(i)=='%' ||input.charAt(i)=='^' ){ if (tempStack.isEmpty()||tempStack.getTop()=='(' ||getState(input.charAt(i))>getState(tempStack.getTop())){ tempStack.push(input.charAt(i)); }else { while (!tempStack.isEmpty()&&getState(input.charAt(i))<getState(tempStack.getTop())){ stringArr[j++]= String.valueOf(tempStack.getTop()); suffix+=tempStack.pop(); } tempStack.push(input.charAt(i)); } } else if (input.charAt(i)=='(' ){ tempStack.push(input.charAt(i)); } else if (input.charAt(i)==')' ){ while (tempStack.getTop()!='(' ){ stringArr[j++]= String.valueOf(tempStack.getTop()); suffix+=(tempStack.pop()); } tempStack.pop(); } } while (!tempStack.isEmpty()){ stringArr[j++]= String.valueOf(tempStack.getTop()); suffix+=(tempStack.pop()); } return suffix; } public double getResult () { double result; for (int i=0 ;i<j;i++){ if (stringArr[i].equals("+" )){ double A= Double.parseDouble(coutStack.pop()); double B= Double.parseDouble(coutStack.pop()); double C= B+A; coutStack.push(String.valueOf(C)); }else if (stringArr[i].equals("-" )){ double A= Double.parseDouble(coutStack.pop()); double B= Double.parseDouble(coutStack.pop()); double C= B-A; coutStack.push(String.valueOf(C)); }else if (stringArr[i].equals("*" )){ double A= Double.parseDouble(coutStack.pop()); double B= Double.parseDouble(coutStack.pop()); double C= B*A; coutStack.push(String.valueOf(C)); }else if (stringArr[i].equals("/" )){ double A= Double.parseDouble(coutStack.pop()); double B= Double.parseDouble(coutStack.pop()); double C= B/A; coutStack.push(String.valueOf(C)); }else if (stringArr[i].equals("!" )){ int A= Integer.parseInt(coutStack.pop()); int B=1 ; while (A!=1 ){ B=B*A; A--; } coutStack.push(String.valueOf(B)); }else if (stringArr[i].equals("%" )){ double A= Double.parseDouble(coutStack.pop()); double B= Double.parseDouble(coutStack.pop()); double C= B%A; coutStack.push(String.valueOf(C)); }else if (stringArr[i].equals("^" )){ double A= Double.parseDouble(coutStack.pop()); double B= Double.parseDouble(coutStack.pop()); double C= Math.pow(B,A); coutStack.push(String.valueOf(C)); } else { coutStack.push(stringArr[i]); } } result= Double.parseDouble(coutStack.pop()); return result; } }
d)调试分析 界面展示
一元多项式运算
项目三:猴子选大王&Joseph环—可视化 a)需求分析: joseph 编号是1,2,„„,n的n个人按照顺时针方向围坐一圈,每个人只有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个仍开始顺时针方向自1开始顺序报数,报到m时停止报数。报m的人出列,将他的密码作为新的m值,从他在顺时针方向的下一个人开始重新从1报数,如此下去,直到所有人全 部出列为止。设计一个程序来求出出列顺序
猴子选大王 n只猴子围坐成一个圈,按顺时针方向从1到n编号。然后从1号猴子开始沿顺时针方向从1开始报数,报到m的猴子出局,再从刚出局猴子的下一个位置重新开始报数,如此重复,直至剩下一个猴子,它就是大王。设计并编写程序,实现如下功能:(1) 要求由用户输入开始时的猴子数n、报数的最后一个数m。(2) 给出当选猴王的初始编号。
b)概要设计: 思路 因为这两个题目比较相近,我写了在一起了,用一个可自定义的大小循环队列的解决一次解决,并将此过程可视化,添加用户交互。
整体设计思路图
在此说明每个部分的算法设计说明(可以是描述算法的流程图),每个程序中使用的存储结构设计说明(如果指定存储结构请写出该存储结构的定义)。
存储结构的设计
c)详细设计: 循环队列设计 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 package com.example.moneyking;public class MySqQueue <E> { int Size; E data[]; int rear=0 ; int front=0 ; int length=0 ; public MySqQueue () { Size=(int )1e6 ; data=(E[])new Object [Size]; } public MySqQueue (int size) { this .Size = size; data=(E[])new Object [Size]; } public boolean isEmpty () { return front==rear&&length==0 ; } public boolean enqueue (E e) { if ((rear+1 )%Size==front){ System.out.println("队满了" ); return false ; } data[rear] = e; rear = (rear+1 )%Size; length++; return true ; } public E dequeue () { if (isEmpty()){ System.out.println("队列为空" ); return null ; } E e = data[front]; front = (front+1 )%data.length; length--; return e; } }
算法设计 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public void show () { MySqQueue<Integer> sqQueue=new MySqQueue <>(MoneyNumber+1 ); for (int i=0 ;i<MoneyNumber;i++){ sqQueue.enqueue(i+1 ); } int count=0 ; while (!sqQueue.isEmpty()){ int temp=sqQueue.dequeue(); System.out.print(temp+" " ); count++; if (count==index){ System.out.println("-------" +temp+"出局" ); count=0 ; }else if (!sqQueue.isEmpty()){ sqQueue.enqueue(temp); } } }
d)调试分析 设置界面
猴子选大王
joseph
课设总结 课程设计过程的收获 这次数据结构课设,让我了解了很多算法的设计,很多数据结构的使用。在设计迷宫时我学习编写使用了队列,双端队列,优先队列,栈,链表,数值和广义表。利用prim算法生成迷宫其实是一个最小生成树也就是传说的完美迷宫,而DFS设计的迷宫则是利用了栈的递归回溯。而迷宫节点设计其实是参考了广义表的设计。在写A星路径规划算法时,则是设计使用了优先队列,通过比较总代价(当前路径+绝对路径)来确定路径方向。在设计计算机项目时,则是使用了栈后进先出的特点,来求解逆波兰式计算算式结果。最后是猴子选大王项目和joseph项目,则是使用了队列的先进先出特点,设计的算法。
对数据结构这门课程的思考 学习数据结构之前、一直以为数据结构是一门新的语言、后来才知道学习数据结构是为了更加高效的的组织数据、设计出良好的算法,而算法则是一个程序的灵魂。经过了一学期的数据结构了,在期末之际对其进行总结。首先,学完数据结构我们应该知道数据结构讲的是什么,数据结构课程主要是研究非数值计算的研究的程序设计问题中所出现的计算机处理对象以及它们之间关系和操作的学科。