java 数据结构实例_数据结构(Java)——栈的实例
惟大英雄能本色,是真名士自风流
——易中天(百家讲坛)
1.表达式的转换
1.1 中缀表达式转前缀表达式
中缀表达式转前缀表达式有许多的方式,有加括号去除法、语法树遍历法、堆栈处理法1.
测试程序的实现:
package ds.java.ch03;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Stack;
/**
*@author LbZhang
*@version 创建时间:2015年11月15日 下午7:14:35
*@description 中缀转化为前缀
*
* 运算符的优先级越低位置越靠前
*/
public class NifixToPrefix {
public static void main(String[] args) {
String expression = "4*3/(5-2)+6";
System.out.println(expression);
char[] temp = expression.toCharArray();
// for (int i = temp.length - 1; i >= 0; i--) {
// System.out.print(temp[i] + " ");
// }
// System.out.println("算法的实现:");
//System.out.println();
// /算法实现
// 1.初始化两个栈
// ///寄存算符
Stack OPTR = new Stack();
// ///中缀转化为前缀
Stack Result = new Stack();
// 2.对存储在字符串Inf ix 中的算术表达式从右左检查每个字符;
for (int i = temp.length - 1; i >= 0; i--) {
// 3.如果是空格直接略过
Character ct = temp[i];
if (ct == ' ') {
continue;
}
// 4.若是操作数, 直接存入RESULT 栈;
if (isOperatorNum(ct)) {
Result.push(ct);
continue;
}
// 5.若为") ", 直接存入OPTR 栈;
if (ct == ')') {
OPTR.push(ct);
continue;
}
/*
* 6.若为'(',循环弹出OPTR栈中算符, 并存入RESULT栈,直到取出')'为止,')'出栈并丢弃;
*/
if (ct == '(') {
Character cc;
while ((cc = OPTR.pop()) != ')') {
Result.push(cc);
}
continue;
}
/*
* 7.若为算符, 则: ①若OPTR 栈为空, 则存入OPTR 栈; ②若该算符较栈顶算符优先级高或相等, 存入OPTR 栈;
* ③否则循环弹出OPTR栈中算符,并存入RESULT 栈, 直至遇到优先级相等的算符
*/
if (isOperator(ct)) {
if (OPTR.isEmpty()) {
OPTR.push(ct);
continue;
} else if (levelOf(ct) >= levelOf(OPTR.peek())) {
OPTR.push(ct);
continue;
} else {
Character cc = OPTR.peek();
while (levelOf(cc) > levelOf(ct) && (!OPTR.isEmpty())) {
Result.push(OPTR.pop());
}
OPTR.push(ct);
}
continue;
}
/*
* 8. 若当前表达式尚未扫描完毕, 跳转到步骤(3) 继续执行;
*/
}
//System.out.println("??"+Result);
/*
* 9.若表达式读取完成后OPTR栈中尚有运算符, 则依次弹出, 并存入RESU LT 栈, 直至栈空;
*/
while (!OPTR.isEmpty()) {
Result.push(OPTR.pop());
}
/*
* 10.RESULT 栈中元素依次出栈并存入字符串prefix 中, 并向prefix 中写入字符串结束符 ,
* 这样字符串prefix中存放的就是转换得到的前缀表达式。
*/
StringBuilder sb = new StringBuilder();
while(!Result.isEmpty()){
sb.append(Result.pop());
}
String re = sb.toString();
System.out.println("前缀表达式:"+re);
}
/**
* 计算当前的算符的优先级
*@param op
*@return
*/
private static int levelOf(Character op) {
int level;
switch (op) {
case '+':
case '-':
level = 1;
break;
case '*':
case '/':
level = 2;
break;
default:
level = 0;
break;
}
return level;
}
/**
* 判断输入串中的字符是不是数字,如果是返回true
*
*@param op
*@return
*/
private static boolean isOperator(Character op) {
if (op == '+' || op == '-' || op == '*' || op == '/')
return true;
else
return false;
}
/**
* 判断输入串中的字符是不是操作符,如果是返回true
*
*@param op
*@return
*/
private static boolean isOperatorNum(Character op) {
if (op >= 48 && op <= 57) {// /0-9的ascii码
return true;
} else {
return false;
}
}
}
1.2 中缀表达式转后缀表达式
中缀表达式转后缀表达式有许多的方式,有加括号去除法、语法树遍历法、堆栈处理法2.
package ds.java.ch03;
import java.util.Stack;
/**
*@author LbZhang
*@version 创建时间:2015年11月15日 下午7:14:53
*@description 类说明
*/
public class NifixToPostfix {
public static void main(String[] args) {
String expression = "4*3/(5-2)+6";
System.out.println(expression);
char[] temp = expression.toCharArray();
// /算法实现
// 1.初始化两个栈
// ///寄存算符
Stack OPTR = new Stack();
// ///中缀转化为后缀
Stack Result = new Stack();
// 2.对存储在字符串Inf ix 中的算术表达式从左向右检查每个字符;
for (int i = 0; i
// 3.如果是空格直接略过
Character ct = temp[i];
//System.out.println(ct);
if (ct == ' ') {
continue;
}
// 4.若是操作数, 直接存入RESULT 栈;
if (isOperatorNum(ct)) {
Result.push(ct);
continue;
}
// 5.若为"( ", 直接存入OPTR 栈;
if (ct == '(') {
OPTR.push(ct);
continue;
}
/*
* 6.若为')',循环弹出OPTR栈中算符, 并存入RESULT栈,直到取出')'为止,')'出栈并丢弃;
*/
if (ct == ')') {
Character cc;
while ((cc = OPTR.pop()) != '(') {
Result.push(cc);
}
continue;
}
/*
* 7.若为算符, 则: ①若OPTR 栈为空, 则存入OPTR 栈; ②若该算符较栈顶算符优先级高或相等, 存入OPTR 栈;
* ③否则循环弹出OPTR栈中算符,并存入RESULT 栈, 直至遇到优先级相等的算符
*/
if (isOperator(ct)) {
if (OPTR.isEmpty()) {
OPTR.push(ct);
continue;
} else if (levelOf(ct) >= levelOf(OPTR.peek())) {
OPTR.push(ct);
continue;
} else {
Character cc = OPTR.peek();
while (levelOf(cc) > levelOf(ct) && (!OPTR.isEmpty())) {
Result.push(OPTR.pop());
}
OPTR.push(ct);
}
continue;
}
/*
* 8. 若当前表达式尚未扫描完毕, 跳转到步骤(3) 继续执行;
*/
}
//System.out.println("??"+Result);
/*
* 9.若表达式读取完成后OPTR栈中尚有运算符, 则依次弹出, 并存入RESULT 栈, 直至栈空;
*/
while (!OPTR.isEmpty()) {
Result.push(OPTR.pop());
}
/*
* 10.RESULT 栈中元素依次出栈并存入字符串
* 然后将字符串逆置
*/
System.out.println(Result);
StringBuilder sb = new StringBuilder();
while(!Result.isEmpty()){
sb.append(Result.pop());
}
String re = sb.toString();
char[] array = re.toCharArray();
String reResult="";
for(int i=array.length-1;i>=0;i--){
reResult+=array[i];
}
System.out.println("后缀表达式:"+reResult);
/*
* 另外一种翻转字符串的方法
*/
// StringBuffer bu = new StringBuffer(re).reverse();
// System.out.println(bu);
}
/**
* 计算当前的算符的优先级
*
*@param op
*@return
*/
private static int levelOf(Character op) {
int level;
switch (op) {
case '+':
case '-':
level = 1;
break;
case '*':
case '/':
level = 2;
break;
default:
level = 0;
break;
}
return level;
}
/**
* 判断输入串中的字符是不是数字,如果是返回true
*
*@param op
*@return
*/
private static boolean isOperator(Character op) {
if (op == '+' || op == '-' || op == '*' || op == '/')
return true;
else
return false;
}
/**
* 判断输入串中的字符是不是操作符,如果是返回true
*
*@param op
*@return
*/
private static boolean isOperatorNum(Character op) {
if (op >= 48 && op <= 57) {// /0-9的ascii码
return true;
} else {
return false;
}
}
}
1.3 前缀表达式与后缀表达式比较
前缀表达式:也被称为波兰表示法,其特点是将操作符置于操作数之前。后缀表达式:又被称为逆波兰法,其特点是将操作符置于操作数之后。
二者都需要两个栈作为辅助空间。
前缀表达式在求解的时候和后缀表达式不一样,前缀表达式在求解扫描的时候是从右侧开始的和后缀表达式截然相反。
2.表达式的求解
2.1 前缀表达式求解
package ds.java.ch03;
import java.util.Scanner;
import java.util.Stack;
/**
*@author LbZhang
*@version 创建时间:2015年11月14日 下午10:17:07
*@description 类说明
*/
public class PrefixEvaluator {
private final static char ADD = '+';
private final static char SUB = '-';
private final static char MUL = '*';
private final static char DIV = '/';
private Stack stack;
public PrefixEvaluator() {
stack = new Stack();
}
/**
* 找到最右边的操作符(即最先运算的操作符),取其右边的两个操作数进行运算,然后找右边第二个操作符,以此类推。
*@param expression
*@return
*/
public int evaluate(String expression) {
int op1, op2, result = 0;
String token;
Scanner parser = new Scanner(expression);
while (parser.hasNext()) {
token = parser.next();
if (isOperator(token)) {
op1 = (stack.pop()).intValue();
op2 = (stack.pop()).intValue();
result = evaluateSingleOperator(token.charAt(0), op1, op2);
stack.push(result);
} else {
stack.push(new Integer(Integer.parseInt(token)));
}
}
return result;
}
private int evaluateSingleOperator(char operation, int op1, int op2) {
int result = 0;
switch (operation) {
case ADD:
result = op1 + op2;
break;
case SUB:
result = op1 - op2;
break;
case MUL:
result = op1 * op2;
break;
case DIV:
result = op1 / op2;
break;
}
return result;
}
/**
* 判断是否是运算符
*
*@param token
*@return
*/
private boolean isOperator(String token) {
return (token.equals("+") || token.equals("-") || token.equals("*") || token
.equals("/"));
}
}
2.2 后缀表达式求解
package ds.java.ch03;
import java.util.Scanner;
import java.util.Stack;
/**
*@author LbZhang
*@version 创建时间:2015年11月14日 下午10:17:07
*@description 类说明
*/
public class PostfixEvaluator {
private final static char ADD = '+';
private final static char SUB = '-';
private final static char MUL = '*';
private final static char DIV = '/';
private Stack stack;
public PostfixEvaluator() {
stack = new Stack();
}
public int evaluate(String expression) {
int op1, op2, result = 0;
String token;
Scanner parser = new Scanner(expression);
while (parser.hasNext()) {
token = parser.next();
//System.out.println(token);
if (isOperator(token)) {
op2 = (stack.pop()).intValue();
op1 = (stack.pop()).intValue();
result = evaluateSingleOperator(token.charAt(0), op1, op2);
stack.push(result);
} else {
stack.push(new Integer(Integer.parseInt(token)));
}
}
return result;
}
private int evaluateSingleOperator(char operation, int op1, int op2) {
int result = 0;
switch (operation) {
case ADD:
result = op1 + op2;
break;
case SUB:
result = op1 - op2;
break;
case MUL:
result = op1 * op2;
break;
case DIV:
result = op1 / op2;
break;
}
return result;
}
/**
* 判断是否是运算符
*
*@param token
*@return
*/
private boolean isOperator(String token) {
return (token.equals("+") || token.equals("-") || token.equals("*") || token
.equals("/"));
}
}
2.3 main测试类
package ds.java.ch03;
import java.util.Scanner;
/**
*@author LbZhang
*@version 创建时间:2015年11月14日 下午4:09:56
*@description 后缀实现
*/
public class Tester {
public static void main(String[] args) {
//前缀测试
int preresult;
// /获取输入流中的内容
/**
* 后缀表达式计算
*/
//中缀表达式 4*3/(5-2)+6
PrefixEvaluator preEvaluator = new PrefixEvaluator();
String prefix = " + / * 4 3 - 5 2 6";
System.out.println("前缀表达式:"+prefix);
// 计算结果存储
StringBuffer prefixb = new StringBuffer(prefix).reverse();
preresult = preEvaluator.evaluate(prefixb.toString());
System.out.println();
System.out.println("前缀表达式的结果: " + preresult);
System.out.println("----------------------分隔线------------------------");
后缀测试
int postresult;
// /获取输入流中的内容
/**
* 后缀表达式计算
*/
//中缀表达式 4*3/(5-2)+6
PostfixEvaluator postEvaluator = new PostfixEvaluator();
String postfix = "4 3 5 2 - / * 6 +";
System.out.println("后缀表达式:"+postfix);
// 计算结果存储
postresult = postEvaluator.evaluate(postfix);
System.out.println();
System.out.println("后缀表达式的结果: " + postresult);
}
}
3.链式结构
链式结构是一种数据结构,它使用对象引用变量来创建对象之间的链接。链式结构是基于数据集合实现的主要替代方案。链表由一些对象构成,其中每个对象指向链表中的下一个对象3。
- 访问链表:从头结点开始不断的遍历
- 插入结点:处理第一个结点需要注意,引入哨兵结点
- 删除结点:处理第一个结点需要注意,引入哨兵结点
4.迷宫求解
栈的另一种经典的使用是,跟踪穿越迷宫的各种可能性,或者其他包含尝试和错误的类似算法。
下面实现一个穿越迷宫基于栈的解决方案:
4.1 Maze.java初始化迷宫矩阵
package ds.java.ch03;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
/**
*@author LbZhang
*@version 创建时间:2015年11月16日 上午11:31:34
*@description 迷宫类
*/
public class Maze {
private static final int TRIED = 2;
private static final int PATH = 3;
private int numRows, numColumns;// 矩阵的行 、 列
private int[][] grid = {
{ 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1 },
{ 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1 },
{ 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0 },
{ 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1 },
{ 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1 },
{ 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1 },
{ 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } };
public Maze() {
this.numRows = grid.length;
this.numColumns = grid[0].length;
}
public Maze(String filename) throws FileNotFoundException{
Scanner scan = new Scanner(new File(filename));
this.numRows = scan.nextInt();
this.numColumns = scan.nextInt();
grid = new int[numRows][numColumns];
for(int i=0;i
for(int j = 0;j
grid[i][j] = scan.nextInt();
}
}
}
public void tryPosition(int row,int col){
grid[row][col] = TRIED;
}
public void makePath(int row,int col){
grid[row][col] = PATH;
}
public boolean valid (int row, int column)
{
boolean result = false;
if (row >= 0 && row < grid.length &&
column >= 0 && column < grid[row].length)
if (grid[row][column] == 1)
result = true;
return result;
}
public String toString ()
{
String result = "\n";
for (int row=0; row < grid.length; row++)
{
for (int column=0; column < grid[row].length; column++)
result += grid[row][column] + "";
result += "\n";
}
return result;
}
public int getRows(){
return this.numRows;
}
public int getColumns(){
return this.numColumns;
}
}
4.2 MazeSlover.java回溯法
package ds.java.ch03;
import ds.java.ch03.stackImpl.LinkedStack;
import ds.java.ch03.stackImpl.StackADT;
/**
*@author LbZhang
*@version 创建时间:2015年11月16日 下午2:49:38
*@description 迷宫路径发现的封装类
*/
public class MazeSlover {
private Maze maze;
/*
* 构造方法
*/
public MazeSlover(Maze maze) {
this.maze = maze;
}
/**
* 遍历方法
*
*@return
*/
public boolean traverse() {
boolean done = false;
Position pos = new Position();
Object dispose;
StackADT stack = new LinkedStack();
// /路径栈 想办法实现
stack.push(pos);
while (!(done) && (!stack.isEmpty())) {
pos = stack.pop();
maze.tryPosition(pos.getX(), pos.getY());
if (pos.getX() == maze.getRows() - 1
&& pos.getY() == maze.getColumns() - 1)
done = true; // the maze is solved
else {
stack = push_new_pos(pos.getX() - 1, pos.getY(), stack);
stack = push_new_pos(pos.getX() + 1, pos.getY(), stack);
stack = push_new_pos(pos.getX(), pos.getY() - 1, stack);
stack = push_new_pos(pos.getX(), pos.getY() + 1, stack);
}
}
return done;
}
/**
* 使用回溯法 来对迷宫进行求解
* 可使用回溯方法,即从入口出发,顺着某一个方向进行探索,若能走通,则继续往前进;
* 否则沿着原路退回,换一个方向继续探索,直至出口位置,求得一条通路。假如所有可能
* 的通路都探索到而未能到达出口,则所设定的迷宫没有通路。
*
*@return
*/
public String findPathForMaze() {
boolean done = false;
//路径栈的声明
StackADT stack = new LinkedStack();
Position pos = new Position();
stack.push(pos);
maze.makePath(pos.getX(), pos.getY());
while(!(done) && (!stack.isEmpty())){
pos = stack.peek();///获取当前的坐标
maze.tryPosition(pos.getX(), pos.getY());///已经走过
if (pos.getX() == maze.getRows() - 1
&& pos.getY() == maze.getColumns() - 1){
done = true; // the maze is solved
break;
}
if(maze.valid(pos.getX(), pos.getY()+1)){
Position p = new Position(pos.getX(), pos.getY()+1);
stack.push(p);
}else if(maze.valid(pos.getX(), pos.getY()-1)){
Position p = new Position(pos.getX(), pos.getY()-1);
stack.push(p);
}else if(maze.valid(pos.getX()+1, pos.getY())){
Position p = new Position(pos.getX()+1, pos.getY());
stack.push(p);
}else if(maze.valid(pos.getX()-1, pos.getY())){
Position p = new Position(pos.getX()-1, pos.getY());
stack.push(p);
}else{
//四个方向都不存在有效的下一坐标那么就出栈
stack.pop();
if(stack.isEmpty()){
break;
}
}
}
if(stack.isEmpty()){
System.out.println("No way");
}else{
System.out.println("OK ");
}
Position pp;
StringBuffer sb = new StringBuffer();
while(!stack.isEmpty()){
pp=stack.pop();
sb.append(pp+"
//路径栈的相关的坐标修改标志数据
maze.makePath(pp.getX(), pp.getY());
}
System.out.println(maze);
return sb.toString().substring(0, sb.toString().length()-2);
}
private StackADT push_new_pos(int x, int y,
StackADT stack) {
Position npos = new Position();
npos.setX(x);
npos.setY(y);
if (maze.valid(x, y)) {
stack.push(npos);
}
return stack;
}
}
4.3 MazeTester.java测试主类
package ds.java.ch03;
/**
*@author LbZhang
*@version 创建时间:2015年11月16日 下午2:49:53
*@description 类说明
*/
public class MazeTester {
public static void main(String[] args) {
System.out.println("-----------**---迷宫遍历的路径---**-------------");
Maze maze = new Maze();
System.out.println(maze);
System.out.println("-------------------原始的迷宫矩阵----------------");
MazeSlover ms = new MazeSlover(maze);
System.out.println(ms.findPathForMaze());
}
}
4.4 Position.java辅助类
package ds.java.ch03;
/**
*@author LbZhang
*@version 创建时间:2015年11月16日 下午2:45:16
*@description
* 坐标类的设计
*/
public class Position {
private int x;
private int y;
public Position(){
x=0;
y=0;
}
public Position(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;
}
@Override
public String toString() {
return "["+this.x+","+this.y+"]";
}
}
曹晓丽. 将中缀表达式转换为前缀表达式的三种方法。 ↩
严晶晶张涛. 将中缀表达式转换成后缀表达式的三种
方法. 计算机与网络. ↩
java 数据结构实例_数据结构(Java)——栈的实例相关推荐
- C语言中用链表构建栈讲解,C语言数据结构之使用链表模拟栈的实例
C语言数据结构之使用链表模拟栈的实例 以下是"使用链表模拟栈"的简单示例: 1. 用C语言实现的版本 #include #include typedef char datatype ...
- java环形链表_数据结构和算法(四)Java实现环形链表
1. 数据结构和算法(四)Java实现环形链表 1.1 约瑟夫问题 约瑟夫问题:公元66年,约瑟夫不情愿地参与领导了犹太同胞反抗罗马统治的起义,后来起义失败,他和一些宁死不降的起义者被困于一个山洞之中 ...
- java 实现违章_基于JAVA的车辆违章查询数据调用代码实例
基于JAVA的车辆违章查询数据调用代码实例 代码描述:基于JA V A的车辆违章查询数据调用代码实例 相关平台:聚合数据 import java.io.BufferedReader; import j ...
- java 单例模式 泛型_设计模式之架构设计实例(工厂模式、单例模式、反射、泛型等)...
设计模式, 架构设计实例, 使用到了工厂模式.单例模式.反射.泛型等 项目包结构如下图: 1.bean包 (1)Base.java父类 package test.bean; public class ...
- dota是java中的_用java开发dota英雄最华丽的技能(实例讲解)
爱java 爱dota,突发奇想想用java开发dota操作最华丽的英雄之一的卡尔的技能,因为本人系小白,代码不足的地方还请包涵,有同样爱好的同学欢迎一起研究学习. 先把我的代码呈上 import j ...
- java查询序列_基于JAVA的苹果序列号查询api调用代码实例
代码描述:基于JAVA的苹果序列号查询api调用代码实例 关联数据:苹果序列号 接口地址:http://www.juhe.cn/docs/api/id/37 1.[代码][Java]代码 import ...
- 编写java判断闰年_用Java程序判断是否是闰年的简单实例
我们知道,(1)如果是整百的年份,能被400整除的,是闰年:(2)如果不是整百的年份,能被4整除的,也是闰年.每400年,有97个闰年.鉴于此,程序可以作以下设计: 第一步,判断年份是否被400整除, ...
- java反射实例_关于java反射的一个案例
案例: *需求:"写一个框架",可以帮我们创建任意类的对象,并且执行其中任意的方法. *实现: 1.配置文件 2.反射 *步骤: 1.将需要创建的对象的全类名和需要执行的方法定义在 ...
- 泛型java实例_【Java学习笔记】Java6泛型实例
你若是不使用泛型,则会这样处理数据类型不确定的问题: class Stash { private Object x; void set(Object x) { this.x = x; } Object ...
最新文章
- 微信支付回调重复通知,正确的响应
- db2数据库连接数 linux_linux db2 连接数据库
- caffe-fast-rcnn(Caffe、FSRCNN、FastRCNN)
- 系统进入低功耗的配置
- Ex 2_5 求解递推式..._第三次作业
- Redis Sentinel集群部署
- 计算机技能鉴定几月考,计算机等级考试和职业技能鉴定考核大纲(二级Office).docx...
- 前端学习(799):根据位置返回字符
- linux下安装php两种模式区别
- loj#6436. 「PKUSC2018」神仙的游戏(NTT)
- 2021大二实训part01
- 5.业务架构·应用架构·数据架构实战 --- 业务驱动的数据架构设计
- 使用Redis存取数据+数据库存取(spring+java)
- PHP实现敏感词过滤
- 微信小程序与普通网页区别
- 测试方法介绍-计算模型复杂度(GMac)、模型大小(M)、计算速度(FPS)
- Python语言程序设计(嵩天老师)-期末考试3.2-站队顺序输出
- [视觉实战案例]Qt下BYTE、QImage、HObject、Mat等图像格式的转换和图像显示方法
- Linux-启动和服务(service)
- 如何关闭或者切换win10的简繁体切换快捷键