
代码
//定义一个栈
class ArrayStack{
private int maxSize;//栈的大小
private int[] stack; //模拟栈的数组
private int top = -1;//初始化为栈顶
public ArrayStack(int maxSize) {
this.maxSize = maxSize;
stack = new int[this.maxSize];
}
//栈满
public boolean ifFull(){
return top == maxSize -1;
}
//栈空
public boolean isEmpty(){
return top == -1;
}
public void push(int value){
if (ifFull()){
System.out.println("栈满");
return;
}
//压栈
top ++;
stack[top] = value;
}
public int pop(){
if (isEmpty()){
throw new RuntimeException("栈空,没有数据");
}
int res = stack[top];
top --;
return res;
}
//遍历
public void list(){
if (isEmpty()){
System.out.println("栈空,没有数据");
}
for (int i = top; i>= 0; i--){
System.out.print(stack[i] + " ");
}
System.out.println();
}
}
public class LinkedStackDemo {
public static void main(String[] args) {
LinkedStack linkedStack = new LinkedStack();
linkedStack.push(1);
linkedStack.push(2);
linkedStack.show();
Node head = linkedStack.getHead();
reverseLinked(head);
linkedStack.show();
}
public static void reverseLinked(Node head){
Node cur = head.getNext();
Node next = null;
Node reverse = new Node();
while(cur != null){
next = cur.getNext();
cur.setNext(reverse.getNext());
reverse.setNext(cur);
cur = next;
}
head.setNext(reverse.getNext());
}
}
//链栈
class LinkedStack{
//定义一个头节点
Node head = new Node();
public Node getHead(){
return head;
}
//定义栈大小
private int maxSize = 5;
private int top = -1;
public boolean isFull(){
return top == maxSize-1;
}
public boolean isEmpty(){
return top == -1;
}
public void push(int value){
Node temp = head;
if (isFull()){
return;
}
while (temp.getNext()!=null){
temp = temp.getNext();
}
Node res = new Node(value);
temp.setNext(res);
top ++;
}
public void show(){
Node temp = head.getNext();
if (isEmpty()){
return;
}
while (temp != null){
System.out.print(temp.getData() + " ");
temp = temp.getNext();
}
System.out.println();
}
public int pop(){
Node temp = head;
if (isEmpty()){
return -1;
}
top --;
temp = temp.getNext();
int res = temp.getData();
System.out.println("出栈的数为" + res);
return res;
}
}
class Node{
private int data;
private Node next;
public Node() {
}
public Node(int data) {
this.data = data;
}
public Node(Node next) {
this.next = next;
}
//省略getter、setter方法
}

1.准备一个索引index来帮助我们遍历表达式
2.如果index位置上的元素是一个数字,就直接入栈
3.如果index位置上的元素是一个符号
4.当表达式遍历完毕后,就弹出数栈中的2个数字和符号栈中的1个符号进行运算,并将运行结果入栈
5.最终数栈中只有一个值,这个值便是运算结果
注意:
读取的是字符,所以存入数字前需要减去0的ASCII码
如果数字是多位数,需要一直读,读到下一位不是数字为止,然后将读到的字符进行拼接,然后一起压入数栈
public class StackCounter {
public static void main(String[] args) {
String experssion = "7+2*6-2";
//创建两个栈
ArrayStack2 numberStack = new ArrayStack2(10);
ArrayStack2 operStack = new ArrayStack2(10);
int index = 0;//用于扫描
int num1 = 0, num2 = 0;
int oper = 0;
int res = 0;
char ch =' ' ;//将每次扫描得到的char放入
//开始循环
while(true){
//依次得到每一个字符
ch = experssion.substring(index,index+1).charAt(0);
//判断ch是什么,然后做相应的处理
if(operStack.isOper(ch)){//如果是符号
if (!operStack.isEmpty()){//如果符号栈不为空
//如果是符号,进行比较,如果当前操作符的优先级小于或等于栈中运算符
if (operStack.priority(ch) <=operStack.priority(operStack.pick())) {
num1 = numberStack.pop();
num2 = numberStack.pop();
oper = operStack.pop();
res = numberStack.cal(num1,num2,oper);
numberStack.push(res);
operStack.push(ch);
}else {
operStack.push(ch);
}
}else{
//如果为空直接入栈
operStack.push(ch);//如果
}
}else{//如果是数,则直接入栈
numberStack.push(ch - 48);//ASCII码转换为数字
}
//index+1.是否扫描到expersion最后
index++;
if (index >= experssion.length()){
break;
}
}
while(true){
//如果符号栈为空,则结算结束,数栈中只有一个数字
if (operStack.isEmpty()){
break;
}
num1 = numberStack.pop();
num2 = numberStack.pop();
oper = operStack.pop();
res = numberStack.cal(num1,num2,oper);
numberStack.push(res);
}
//将数栈中最后一个打印出来
System.out.println("表达式为:"+experssion+"结果为:"+numberStack.pop());
}
}
//先创建一个栈,需要扩展功能
class ArrayStack2{
private int maxSize;//栈的大小
private int[] stack; //模拟栈的数组
private int top = -1;//初始化为栈顶
public ArrayStack2(int maxSize) {
this.maxSize = maxSize;
stack = new int[this.maxSize];
}
//栈满
public boolean ifFull(){
return top == maxSize -1;
}
//栈空
public boolean isEmpty(){
return top == -1;
}
public void push(int value){
if (ifFull()){
System.out.println("栈满");
return;
}
top ++;
stack[top] = value;
}
public int pop(){
if (isEmpty()){
throw new RuntimeException("栈空,没有数据");
}
int res = stack[top];
top --;
return res;
}
//遍历
public void list(){
if (isEmpty()){
System.out.println("栈空,没有数据");
}
for (int i = top; i>= 0; i--){
System.out.print(stack[i] + " ");
}
System.out.println();
}
//返回运算符的优先级,优先级使用数字表示,数字越大,优先级越高
public int priority(int oper){
if (oper == '*' || oper =='/'){
return 1;
}else if(oper == '+' || oper == '-'){
return 0;
}else {
return -1;//假定只有+ - * /
}
}
//判断是否为运算符
public boolean isOper(char val){
return val == '+'||val == '-'||val == '*'||val == '/';
}
//计算方法
public int cal(int num1,int num2,int oper){
int res = 0;
switch (oper){
case '+':
res = num1 + num2;
break;
case '-':
res = num2-num1;
break;
case '*':
res = num1*num2;
break;
case '/':
res = num2/num1;
break;
default:
break;
}
return res;
}
//返回当前栈顶的方法
public int pick(){
return stack[top];
}
}
public class StackCounter {
public static void main(String[] args) {
String experssion = "70+2*6-4+8";
//创建两个栈
ArrayStack2 numberStack = new ArrayStack2(10);
ArrayStack2 operStack = new ArrayStack2(10);
int index = 0;//用于扫描
int num1 = 0, num2 = 0;
int oper = 0;
int res = 0;
String s = "";//用于拼接多位数
char ch = ' ';//将每次扫描得到的char放入
//开始循环
while (true) {
//依次得到每一个字符
ch = experssion.substring(index, index + 1).charAt(0);
//判断ch是什么,然后做相应的处理
if (operStack.isOper(ch)) {//如果是符号
if (!operStack.isEmpty()) {//如果符号栈不为空
//如果是符号,进行比较,如果当前操作符的优先级小于或等于栈中运算符
if (operStack.priority(ch) <= operStack.priority(operStack.pick())) {
num1 = numberStack.pop();
num2 = numberStack.pop();
oper = operStack.pop();
res = numberStack.cal(num1, num2, oper);
numberStack.push(res);
operStack.push(ch);
} else {
//否则直接入栈
operStack.push(ch);
}
}else{
operStack.push(ch);
}
}else {//如果是数,则直接入栈
//当处理多位数时,不能发现是一个数就立即入栈,在处理数时,需要向expression的表达式再看一位index,如果是符号就可以入栈
//需要定义一个字符串变量用于拼接。
s += ch;
//是否是表达式的最后一位
if (index == experssion.length() - 1) {
numberStack.push(Integer.parseInt(s));
} else {
//判断下一个字符是不是数字,如果是数字就继续扫描
if (operStack.isOper(experssion.substring(index + 1, index + 2).charAt(0))) {
//如果是符号就可以入栈
numberStack.push(Integer.parseInt(s));//字符串转为整数
//清空s
s = "";
}
}
}
//index+1.是否扫描到expersion最后
index++;
if (index >= experssion.length()) {
break;
}
}
while (true) {
//如果符号栈为空,则结算结束,数栈中只有一个数字
if (operStack.isEmpty()) {
break;
}
num1 = numberStack.pop();
num2 = numberStack.pop();
oper = operStack.pop();
res = numberStack.cal(num1, num2, oper);
numberStack.push(res);
}//将数栈中最后一个打印出来
System.out.println("表达式为:" + experssion + "结果为:" + numberStack.pop());
}
}
//先创建一个栈,需要扩展功能
class ArrayStack2{
private int maxSize;//栈的大小
private int[] stack; //模拟栈的数组
private int top = -1;//初始化为栈顶
public ArrayStack2(int maxSize) {
this.maxSize = maxSize;
stack = new int[this.maxSize];
}
//栈满
public boolean ifFull(){
return top == maxSize -1;
}
//栈空
public boolean isEmpty(){
return top == -1;
}
public void push(int value){
if (ifFull()){
System.out.println("栈满");
return;
}
top ++;
stack[top] = value;
}
public int pop(){
if (isEmpty()){
throw new RuntimeException("栈空,没有数据");
}
int res = stack[top];
top --;
return res;
}
//遍历
public void list(){
if (isEmpty()){
System.out.println("栈空,没有数据");
}
for (int i = top; i>= 0; i--){
System.out.print(stack[i] + " ");
}
System.out.println();
}
//返回运算符的优先级,优先级使用数字表示,数字越大,优先级越高
public int priority(int oper){
if (oper == '*' || oper =='/'){
return 1;
}else if(oper == '+' || oper == '-'){
return 0;
}else {
return -1;//假定只有+ - * /
}
}
//判断是否为运算符
public boolean isOper(char val){
return val == '+'||val == '-'||val == '*'||val == '/';
}
//计算方法
public int cal(int num1,int num2,int oper){
int res = 0;
switch (oper){
case '+':
res = num1 + num2;
break;
case '-':
res = num2-num1;
break;
case '*':
res = num1*num2;
break;
case '/':
res = num2/num1;
break;
default:
break;
}
return res;
}
//返回当前栈顶的方法
public int pick(){
return stack[top];
}
}
存在的问题:因为栈是用的整型数组,所以计算除法的时候,无法转化成double
后缀表达式又称逆波兰表达式,与前缀表达式相似,只是运算符位于操作数之后
| 正常的表达式 | 逆波兰表达式 |
|---|---|
| a+b | a b + |
| a+(b-c) | a b c - + |
| a+(b-c)*d | a b c – d * + |
| a+d*(b-c) | a d b c - * + |
| a=1+3 | a 1 3 + = |

初始化两个栈:运算符栈 s1 和储存中间结果的栈 s2;
从左至右扫描中缀表达式;
遇到操作数时,将其压 s2;
遇到运算符时,比较其与 s1 栈顶运算符的优先级:
如果 s1 为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
否则,若优先级比栈顶运算符的高,也将运算符压入 s1;
否则,将 s1 栈顶的运算符弹出并压入到 s2 中,再次转到(4.1)与 s1 中新的栈顶运算符相比较;
遇到括号时:
重复步骤 2 至 5,直到表达式的最右边
将 s1 中剩余的运算符依次弹出并压入 s2
依次弹出 s2 中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
如“1+((2+3)x 4)-5”;步骤如下
实现
import java.util.*;
public class PolandNatation {
public static void main(String[] args) {
//将中缀表达式转换为后缀表达式
String experssion = "1+((2+3)*4)-5";
List<String> infixExperssionList = toInfixExperssionList(experssion);
System.out.println(infixExperssionList);
List<String> pareSuffixExperssion = parseSuffixExpersion(infixExperssionList);//将中缀表达式转换为后缀表达式
System.out.println(pareSuffixExperssion);
System.out.println("结果为:" + calculate(pareSuffixExperssion));
//定义一个逆波兰表达式
/*String suffixExpression = "4 5 * 8 - 60 + 8 2 / +";
//为了方便,逆波兰表达式的数字和空格隔开
//思路
//先将"3 4 + 5 * 6 -" 放入ArrayList中
//4*5-8+60+8/2
//4 5 * 8 - 60 + 8 2 / +
//将ArrayList传递给一个方法,这个方法使用配合栈完成计算
List rpnList = getListString(suffixExpression);
System.out.println("rpnList " + rpnList);
int res = calculate(rpnList);
System.out.println("计算结果为:" + res);*/
}
//将中缀表达式转换成对应的List
public static List<String> toInfixExperssionList(String s){
List<String> ls = new ArrayList<String>();
int i = 0;//这是一个指针,用于遍历中缀表达式字符串
String str;//多位数字的拼接
char c;//每遍历到一个字符,就放入c
do{
//如果c是一个非数字,就需要加入ls
if ((c = s.charAt(i)) <48 || (c = s.charAt(i)) >57){//不是数
ls.add(String.valueOf(c));
i++;
}else{//如果是一个数们需要考虑多位数问题
str = "";//清空
while(i<s.length() && (c = s.charAt(i)) >= 48 && (c = s.charAt(i)) <= 57){
str += c;
i++;
}
ls.add(str);
}
}while (i < s.length());
return ls;
}
//将得到的中缀表达式对应的list 转换为后缀表达式对应的list
public static List<String> parseSuffixExpersion(List<String> ls){
//定义两个栈
Stack<String> s1 = new Stack<String>();
//因为s2在整个转换过程中没有pop操作,而且还要逆序输出,因此直接使用List
List<String> s2 = new ArrayList<String>();
//遍历ls
for (String item:ls){
if (item.matches("\\d+")){
s2.add(item);
}else if(item.equals("(")){
s1.push(item);
}else if(item.equals(")")){
while(!s1.peek().equals("(")){
s2.add(s1.pop());//s1一次弹出到s2
}
s1.pop();//将(弹出s1 消除(
}else{
//当item运算符的优先级小于s1栈顶运算符的优先级时,s1栈顶的运算符弹出栈,压入到s2
while (s1.size()!= 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item)){
s2.add(s1.pop());
}
//把当前item运算符,压入栈中
s1.push(item);
}
}
while(s1.size()!= 0){
s2.add(s1.pop());
}
return s2;//顺序输出即可
}
//优先级比较高低的方法
//将一个逆波兰表达式,依次将数据和运算符放入ArrayList中
public static List<String> getListString(String suffixExperssion){
//将suffixExperssion分割
String[] split = suffixExperssion.split(" ");//把字符串分隔开
List<String> list = new ArrayList<String>();//创建一个新的序列
for (String ele:split){
list.add(ele);
}
return list;
}
//完成运算
public static int calculate(List<String> ls){
//创建栈,只需要一个栈即可
Stack<String> stack = new Stack<String>();
//遍历list
for(String item:ls){
//使用正则表达式取出数
if (item.matches("\\d+")){//匹配的为多位数
//入栈
stack.push(item);
}else{
//pop出两个数并且运算,在入栈
int num2 = Integer.parseInt(stack.pop());//后弹出-先弹出
int num1 = Integer.parseInt(stack.pop());
int res = 0;
if (item.equals("+")){
res = num1+num2;
}else if(item.equals("-")){
res = num1-num2;
}else if(item.equals("*")){
res = num1*num2;
}else if(item.equals("/")){
res = num1/num2;
}else{
throw new RuntimeException("运算符有误");
}
stack.push(String.valueOf(res));
}
}
return Integer.parseInt(stack.pop());
}
}
//编写一个类
class Operation{
private static int add = 1;
private static int sub = 1;
private static int mul = 2;
private static int div = 2;
public static int getValue(String operation){
int result= 0;
switch (operation){
case "+":
result = add;
break;
case "-":
result = sub;
break;
case "*":
result = mul;
break;
case "/":
result = div;
break;
default:
//System.out.println("不存在该运算符");
break;
}
return result;
}
}
1)支持+-*/()
2)多位数,支持小数,
3)兼容处理,过滤任何空白字符,包括空格、制表符、换页符
参考
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Stack;
import java.util.regex.Pattern;
public class CompersionPolandNatation {
/**
* 匹配 + - * / ( ) 运算符
*/
static final String SYMBOL = "\\+|-|\\*|/|\\(|\\)";
static final String LEFT = "(";
static final String RIGHT = ")";
static final String ADD = "+";
static final String MINUS = "-";
static final String TIMES = "*";
static final String DIVISION = "/";
/**
* 加減 + -
*/
static final int LEVEL_01 = 1;
/**
* 乘除 * /
*/
static final int LEVEL_02 = 2;
/**
* 括号
*/
static final int LEVEL_HIGH = Integer.MAX_VALUE;
static Stack<String> stack = new Stack<>();
static List<String> data = Collections.synchronizedList(new ArrayList<String>());
/**
* 去除所有空白符
*
* @param s
* @return
*/
public static String replaceAllBlank(String s) {
// \\s+ 匹配任何空白字符,包括空格、制表符、换页符等等, 等价于[ \f\n\r\t\v]
return s.replaceAll("\\s+", "");
}
/**
* 判断是不是数字 int double long float
*
* @param s
* @return
*/
public static boolean isNumber(String s) {
Pattern pattern = Pattern.compile("^[-\\+]?[.\\d]*$");
return pattern.matcher(s).matches();
}
/**
* 判断是不是运算符
*
* @param s
* @return
*/
public static boolean isSymbol(String s) {
return s.matches(SYMBOL);
}
/**
* 匹配运算等级
*
* @param s
* @return
*/
public static int calcLevel(String s) {
if ("+".equals(s) || "-".equals(s)) {
return LEVEL_01;
} else if ("*".equals(s) || "/".equals(s)) {
return LEVEL_02;
}
return LEVEL_HIGH;
}
/**
* 匹配
*
* @param s
* @throws Exception
*/
public static List<String> doMatch(String s) throws Exception {
if (s == null || "".equals(s.trim())) throw new RuntimeException("data is empty");
if (!isNumber(s.charAt(0) + "")) throw new RuntimeException("data illeagle,start not with a number");
s = replaceAllBlank(s);
String each;
int start = 0;
for (int i = 0; i < s.length(); i++) {
if (isSymbol(s.charAt(i) + "")) {
each = s.charAt(i) + "";
// 栈为空,(操作符,或者 操作符优先级大于栈顶优先级 && 操作符优先级不是( )的优先级 及是 ) 不能直接入栈
if (stack.isEmpty() || LEFT.equals(each)
|| ((calcLevel(each) > calcLevel(stack.peek())) && calcLevel(each) < LEVEL_HIGH)) {
stack.push(each);
} else if (!stack.isEmpty() && calcLevel(each) <= calcLevel(stack.peek())) {
// 栈非空,操作符优先级小于等于栈顶优先级时出栈入列,直到栈为空,或者遇到了(,最后操作符入栈
while (!stack.isEmpty() && calcLevel(each) <= calcLevel(stack.peek())) {
if (calcLevel(stack.peek()) == LEVEL_HIGH) {
break;
}
data.add(stack.pop());
}
stack.push(each);
} else if (RIGHT.equals(each)) {
// ) 操作符,依次出栈入列直到空栈或者遇到了第一个)操作符,此时)出栈
while (!stack.isEmpty() && LEVEL_HIGH >= calcLevel(stack.peek())) {
if (LEVEL_HIGH == calcLevel(stack.peek())) {
stack.pop();
break;
}
data.add(stack.pop());
}
}
start = i; // 前一个运算符的位置
} else if (i == s.length() - 1 || isSymbol(s.charAt(i + 1) + "")) {
each = start == 0 ? s.substring(start, i + 1) : s.substring(start + 1, i + 1);
if (isNumber(each)) {
data.add(each);
continue;
}
throw new RuntimeException("data not match number");
}
}
// 如果栈里还有元素,此时元素需要依次出栈入列,可以想象栈里剩下栈顶为/,栈底为+,应该依次出栈入列,可以直接翻转整个stack 添加到队列
Collections.reverse(stack);
data.addAll(new ArrayList<>(stack));
System.out.println(data);
return data;
}
/**
* 算出结果
*
* @param list 逆波兰表达是
* @return Double 计算结果
*/
public static Double doCalc(List<String> list) {
Double d = 0d;
if (list == null || list.isEmpty()) {
return null;
}
if (list.size() == 1) {
System.out.println(list);
d = Double.valueOf(list.get(0));
return d;
}
ArrayList<String> list1 = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
list1.add(list.get(i));
if (isSymbol(list.get(i))) {
Double d1 = doTheMath(list.get(i - 2), list.get(i - 1), list.get(i));
list1.remove(i);
list1.remove(i - 1);
list1.set(i - 2, d1 + "");
list1.addAll(list.subList(i + 1, list.size()));
break;
}
}
doCalc(list1);
return d;
}
/**
* 运算
*
* @param s1
* @param s2
* @param symbol
* @return
*/
public static Double doTheMath(String s1, String s2, String symbol) {
Double result;
switch (symbol) {
case ADD:
result = Double.valueOf(s1) + Double.valueOf(s2);
break;
case MINUS:
result = Double.valueOf(s1) - Double.valueOf(s2);
break;
case TIMES:
result = Double.valueOf(s1) * Double.valueOf(s2);
break;
case DIVISION:
result = Double.valueOf(s1) / Double.valueOf(s2);
break;
default:
result = null;
}
return result;
}
/**
* 功能描述:完整版逆波兰计算器测试
*
* @param args 命令行
* @author cakin
* @date 2021/3/6
*/
public static void main(String[] args) {
// String math = "9+(3-1)*3+10/2";
String math = "12.8 + (2 - 3.55)*4+10/5.0";
try {
doCalc(doMatch(math));
} catch (Exception e) {
e.printStackTrace();
}
}
}
递归就是方法自己调用自己,每次调用时传入不同的变量.递归有助于编程者解决复杂的问题,同时可以让代码变得简洁。并且递归用到了虚拟机栈
1. 找整个递归的终止条件:递归应该在什么时候结束?
2. 找返回值:应该给上一级返回什么信息?
3. 本级递归应该做什么:在这一级递归中,应该完成什么任务?
八皇后问题 汉诺塔 求阶乘 迷宫问题 球和篮子 各种排序算法
程序执行到一个方法时,就会开辟一个独立的空间(栈空间),每个空间的数据(局部变量)是独立的
eg.阶乘问题
package com.atguigu.recusion;
public class RecusionTest01 {
public static void main(String[] args) {
//回顾递归的调用机制
System.out.println("res + " + factorial(2));
}
//阶乘问题
public static int factorial(int n) {
if (n == 1) {
return 1;
} else {
return factorial(n - 1) * n; // 1 * 2 * 3
}
}
}
1.执行一个方法时,就创建一个新的受保护的独立空间(栈空间)
2.方法的变量是独立的,不会相互影响的
3.如果方法中使用的是引用类型变量(比如数组),就会共享该引用类型的数据
4.递归必须向退出递归的条件逼近,否则就是无限递归,出现 StackOverflowError
5.当一个方法执行完毕,或者遇到 return,就会返回,遵守谁调用,就将结果返回给谁,同时当方法执行完毕或者返回时,该方法也就执行完毕
package com.atguigu.recusion;
public class MiGongTest01 {
public static void main(String[] args) {
//先创建一个二维数组
//地图
int[][] map = new int[8][7];
//使用1表示墙
//先把上下置为1
for(int i = 0;i<7;i++){
map[0][i] = 1;
map[7][i] = 1;
}
//左右全部置为1
for (int i = 0;i<8;i++){
map[i][0] = 1;
map[i][6] = 1;
}
//设置障碍
map[3][1] = 1;
map[3][2] = 1;
//输出地图
System.out.println("------MAP-----");
for(int i = 0; i <8 ;i++) {
for (int j = 0; j < 7; j++) {
System.out.print(map[i][j] + " ");
}
System.out.println();
}
//使用递归
setWay(map,1,1);
//输出新的地图,小球走过的通路
System.out.println("------NEWMAP-----");
for(int i = 0; i <8 ;i++) {
for (int j = 0; j < 7; j++) {
System.out.print(map[i][j] + " ");
}
System.out.println();
}
}
/**
* 如果小球可以到达map[6][5],则说明通路找到
* 约定:当map[i][j]为0表示该点没有走过,1的时候为墙;2的时候表示一个通路;3表示该点探测过了,但是不通
* 走迷宫时候的策略:下 右 上 左,如果该点走不通在回溯
* @param map 地图
* @param i 起始位置
* @param j
* @return
*/
public static boolean setWay(int[][] map, int i,int j){
if(map[6][5] == 2){
return true;
}else {
if (map[i][j] == 0){//如果当前点还没有走过
//按照策略走 下 右 上 左
map[i][j] = 2;//假定该店可以走通
if(setWay(map,i+1,j)){//先向下走
return true;
}else if(setWay(map,i,j+1)){
return true;
}else if(setWay(map,i-1,j)){
return true;
}else if(setWay(map,i,j-1)){
return true;
}else {
map[i][j] = 3;//说明该点是走不通的
return false;
}
}else {
return false;
}
}
}
}
package ch4;
import java.util.Scanner;
public class MiGong {
static int n,m,endx,endy,min = 99999;
static int[][] a = new int[51][51];
static int[][] book = new int[51][51];
public static void main(String[] args) {
//读入n和m,n为行,m为列
Scanner scanner = new Scanner(System.in);
System.out.println("输入行:");
n = scanner.nextInt();
System.out.println("输入列:");
m = scanner.nextInt();
System.out.println("输入迷宫:");
for (int i =1; i<=n ;i++){
for (int j =1;j<=m;j++){
a[i][j] = scanner.nextInt();
}
}
scanner.close();
int stratx = 1,starty = 1;
endx = n;
endy = m;
//从起点开始搜索
book[stratx][starty] = 1;//标记起点已经在路径中
dfs(stratx,starty,0);
System.out.println("最短的路径 " + min);
}
public static void dfs(int x, int y, int step){
//定义四个方向
int[][] next= {{0,1},{1,0},{0,-1},{-1,0}};
int tx,ty;
//判断是否到达出口
if(x ==endx && y == endy){
//更新最小值
if(step<=min)
min = step;
return;
}
//四种走法
for(int k =0; k<4;k++){
//计算下一个坐标点
tx = x + next[k][0];
ty = y + next[k][1];
//判断是否越界,是否为障碍物,是否在路径中
if(tx < 1|| tx > n || ty <1|| ty > n){
continue;
}
if(a[tx][ty] == 0 && book[tx][ty] == 0){
book[tx][ty] = 1;//标记这个点已经做过了
dfs(tx,ty,step+1);//开始尝试下一个点
book[tx][ty] = 0;//尝试结束,取消这个点的标记
}
}
}
}
八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在 8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即:任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法(92)。
思路
package com.atguigu.recusion;
public class Queue8 {
//定义一个max表示共有多少个皇后
int max = 8;
//定义一个数组array,保存皇后放置位置的结果,比如arr = {0,4,7,5,2,6,1,3}
int[] array = new int[max];
static int count = 0;
static int judgecount = 0;
public static void main(String[] args) {
Queue8 queue8 = new Queue8();
queue8.check(0);
System.out.println(count);
System.out.println(judgecount);
}
//编写一个方法,放置第n个皇后
//check 每一次递归时,都有一次for循环,因此会有回溯
private void check(int n){
if(n == max){//开始放第九个皇后,放置结束
print();
count++;
return;
}
//没有放置结束,依次放入皇后
for (int i =0; i < max ;i++){
//先把当前皇后,放到该行的第1列
array[n] = i;
//判断是否可以放置
if(judge(n)){
check(n+1);
}
//如果冲突就继续执行for循环,直到全部列找完
}
}
//查看当我们放置第n个皇后,就去检测该皇后是否和前面已经摆放完的皇后冲突
/**
*
* @param n 表示要放置的第n个皇后
* @return
*/
public boolean judge(int n){
judgecount ++;
for (int i = 0 ;i <n ; i++){
//第一个条件:判断是否在同一列
//第二个条件:判断是否在同一斜线,如果在同一斜线当前行-行的绝对值 = 当前列- 列的绝对值
//因为n是递增的所以一定不同一行
if(array[i] == array[n] || Math.abs(n-i) == Math.abs(array[n] - array[i]))
return false;
}
return true;
}
//写一个方法将最后摆放的位置打印出来
private void print(){
for (int i=0;i<array.length;i++){
System.out.print(array[i] + " ");
}
System.out.println();
}
}