package stack;
import stack.sq.SqStack;
/**
*
* @author 半步疯子
* 通过迷宫求解,其中出错的问题就是对引用类型变量的理解不够深刻
* 传值和传地址不够明确
* 即使我的引用类型变量被压入栈中,但是我的curpos指向的同样还是对应e中的seat的对象
* 所以这里不能在原来的nextPos方法上进行修改,修改了之后栈中前一步的position也跟着改变了
* 如果当前步(curpos)不是可通过的区域,那么就会pop到上一步,但是上一步已经被修改到和
* 当前位置相同的position了,所以就会造成对角线可通过的情况(因为当前是站在墙“1”上的)
* 0 1 1 1 1
* 1 0 1 1 1(对角线通过,两个0通过;但是迷宫规则,对角线是不能通过的)
*/
public class StackSolveMaze {
/**
* 位置坐标
* @author Administrator
*
*/
private class Position {
// 非静态内部类中不能放静态的字段 static x static y
/*
* int x;
* int y;
* 这里的x和y与传统意义上的x和y不同
* 为了避免混淆,用row和loc的点定义
* 这里的x等价于row(行)
* 这里的y等价于col(列)
* 行号x和列号y刚好与传统的x、y相反
*
*/
int row;
int col;
}
/**
* 栈中的元素类型
* @author Administrator
*
*/
private class StackElem {
int ord; // 通道块在路径上的 序号
Position seat; // 通道块在迷宫中的 坐标位置
int direction; // 从该通道块走向下一个通道块的 方向
}
/**
* 存放经过路径的栈
*/
SqStack stack = new SqStack();
private SqStack getStack() {
return stack;
}
/**
* 存放走过每个点的是否通过的图谱
*/
int[][] footPrint = new int[10][10];
private int[][] getPrintFoot() {
return footPrint;
}
/**
* 原来的迷宫的图
*/
static int[][] maze = {
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 0, 0, 1, 0, 0, 0, 1, 0, 1 },
{ 1, 0, 0, 1, 0, 0, 0, 1, 0, 1 },
{ 1, 0, 0, 0, 0, 1, 1, 0, 0, 1 },
{ 1, 0, 1, 1, 1, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
{ 1, 0, 1, 0, 0, 0, 1, 0, 0, 1 },
{ 1, 0, 1, 1, 1, 0, 1, 1, 0, 1 },
{ 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
};
/**
*
* @param pos
* 位置坐标对象
* @return 是否可以通过
*/
boolean Pass(Position pos) {
// if(maze[pos.row][pos.col])
/*
* maze中的1表示不可通过 footPrint中的1表示可以走 (1为基础值,如果通过则--,如果最后pop则+=2) 0 1 2
* 通过未返回 可通过 通过但是倒回
*/
if (maze[pos.row][pos.col] != 1 && footPrint[pos.row][pos.col] == 1)
return true;
return false;
}
/*
0-------------y col(i)列
|
|
|
|
x
row(j)行
*/
Position nextPos(Position curpos, int direction) {
/*
* 这里应该把向南和向向东分开到四个方向最开始的位置
* 因为只有向东和向南才是有效前进
* 这样可以达到优化
* 假如:
* east = 1;
* south = 2;
* west = 3;
* north = 4;
* 我当前位置的后一个位置不能通过
*/
final int east = 1;
final int south = 2;
final int west = 3;
final int north = 4;
/* 4
* 3 1
* 2
*/
// 搞清楚向南和向东的关系
Position pos = new Position();
pos.col = curpos.col;
pos.row = curpos.row;
if (direction == east)
pos.col++;
if (direction == south)
pos.row++;
if (direction == west)
pos.col--;
if (direction == north)
pos.row--;
return pos;
}
boolean mazePath(Position start, Position end) {
Position curpos = start;
int curstep = 1;
SqStack stack = new SqStack();
// int direction = 1;
StackElem e;
for (int i = 0; i < 10; i++)
for (int j = 0; j < 10; j++)
footPrint[i][j] = 1;
do {
// 当前的位置可以通过
// 没有走过的位置
if (Pass(curpos)) {
footPrint[curpos.row][curpos.col] = 0; // 留下足迹
e = new StackElem();
e.ord = curstep;
e.seat = curpos;
e.direction = 1;
System.out.println("第" + e.ord + "步:" + e.seat.row + "行, " + e.seat.col+"列");
stack.push(e); // 将该点压入栈中
if (curpos.row == end.row && curpos.col == end.col) {
this.stack = stack;
return true; // 若该点为终点,退出
}
curpos = nextPos(curpos, 1);
/*
* 默认的寻找方向是向东的
*/
curstep++; // 探索下一步
}else {
if (!stack.empty()) {
e = stack.pop();
// 若没有这个点,进行回溯
while (4 == e.direction && !stack.empty()) {
footPrint[e.seat.row][e.seat.col] = 2;
// 留下不可通过的标记
e = stack.pop(); // 退回一步
}
// 变换方向
if (e.direction < 4) {
e.direction++;
stack.push(e);
curpos = nextPos(e.seat, e.direction);
// 更新下一个点的信息
}
}
}
} while (!stack.empty());
return false;
}
public static void main(String[] args) {
StackSolveMaze ma = new StackSolveMaze();
StackSolveMaze.Position start = ma.new Position();
StackSolveMaze.Position end = ma.new Position();
start.row = 1;
start.col = 1;
end.row = 8;
end.col = 8;
if (ma.mazePath(start, end)) {
System.out.println("迷宫可以通过");
} else {
System.out.println("迷宫不可通过");
}
System.out.println("查看路径的情况:(0表示走过,2表示走过但是不可取):");
int[][] foot = ma.getPrintFoot();
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
System.out.print(foot[i][j] + " ");
}
System.out.println();
}
System.out.println("迷宫图为:");
for (int row = 0; row < 10; row++) {
for (int loc = 0; loc < 10; loc++) {
System.out.print(maze[row][loc] + " ");
}
System.out.println();
}
SqStack stack = ma.getStack();
while (!stack.empty()) {
StackElem e = (StackElem)stack.pop();
System.out.println("第" + e.ord + "步:" + e.seat.row + "行, " + e.seat.col+"列");
}
}
}
package stack.sq;
import java.util.Arrays;
/**
* 基于数组实现的顺序栈
*
* top 永远指向栈顶元素之上的位置
* top初始值为0 FILO
*
* @author 半步疯子
* @param
*/
public class SqStack {
private Object[] data = null;
private int stackSize = 0; // 栈容量
private int addSize = 10; // 每次增加的基数
private int top = 0; // 栈顶指针(初始化为0,避免对后面造成影响)
//--------------------------
/**
* 初始化栈操作
*
* complete
*/
public SqStack(){
this(10); // 默认栈大小为10
}
public SqStack(int initialSize) throws RuntimeException{
if(initialSize > 0){
this.stackSize = initialSize;
data = new Object[initialSize];
top = 0;
}else{
throw new RuntimeException("初始化大小不合理:" + initialSize);
}
}
//--------------------------
/**
* 获取SqStack的元素个数
* @return 返回表长
*/
public int stackLength() {
return top;
}
/**
* 返回分配的存储长度
* @return 返回表长
*/
public int getCapacity() {
return stackSize;
}
/**
* 当为空的时候,top为0
* @return 空时为true 不空的时候为false
*
* complete
*/
public boolean empty(){
return top == 0;
// return top == 0 ? true : false;
}
/**
* 进栈的操作
* @param e
*
* complete
*/
public void push(E e){
if(top == stackSize) myReallocated();
// throw new RuntimeException("栈已满,无法将元素入栈!");
data[top++]=e;
}
/**
* 查看栈顶元素但不移除
* @return
*
* complete
*/
@SuppressWarnings("unchecked")
public E peek() throws RuntimeException{
if(0 == top){
throw new RuntimeException("栈为空!");
}else{
return (E)data[top-1];
}
}
/**
* 弹出栈顶元素
* @return
*
* complete
*/
@SuppressWarnings("unchecked")
public E pop() throws RuntimeException{
if(0 == top){
throw new RuntimeException("栈为空!");
}else{
E value = (E)data[top-1];
data[--top] = null;
return value;
}
}
/**
* complete
*/
private void myReallocated(){
/*
Object[] temp = new Object[stackSize+addSize];
stackSize = stackSize+addSize;
System.arraycopy(data, 0, temp, 0, data.length);
data = temp;
*/
if(top == stackSize){
stackSize += addSize; //将栈容量加10 或增加到10
data = Arrays.copyOf(data, stackSize); //将原数组进行拷贝
}
}
/**
* complete
*/
@SuppressWarnings("unchecked")
public void stackPrint() {
for(int i=0; i