关于回溯与栈的最初的迷茫之处:刚开始听完迷宫问题求通路的时候,我就有一个疑问:将文件的内容传递给数组,再进行压栈,这两个(数组与栈空间)明明不是同一块空间,为什么当我释放栈的时候,当前路径的尾节点能够变为上一个节点,从而使得上一个节点成为了新路径的尾节点 ?《希望你们能看懂我说的什么意思,嘿嘿》,如果就这么用文字描述答案虽然能说通但是印象并不会太深刻,所以不说废话了。直接上代码。
//Stack.h :这里我自己实现的模板栈
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
template<class T>
class Stack
{
public:
Stack()
:_a(new T[1])
,_sz(0)
,_capacity(0)
{}
~Stack()
{
if(_a)
{
delete[] _a;
_sz = 0;
_capacity = 0;
}
}
public:
void Push(const T& d);
void CheckCapacity();
bool Empty();
void Pop();
T& Top();
void Dislplay();
protected:
T* _a;
int _sz;
int _capacity;
};
template<class T>
void Stack<T>::CheckCapacity ()
{
if(_sz == _capacity )
{
T* tmp =new T[_capacity * 2+ 3];
for(int i = 0; i < _sz;i++)
{
tmp[i] = _a[i];
}
delete[] _a;
_capacity = _capacity * 2 + 3;
_a = tmp;
}
}
template<class T>
void Stack<T>::Push(const T& d)
{
CheckCapacity();
_a[_sz] = d;
_sz++;
}
template<class T>
void Stack<T>::Pop()
{
assert(_sz > 0);
_sz--;
}
template<class T>
T& Stack<T>::Top()
{
return _a[_sz-1];
}
template<class T>
bool Stack<T>::Empty()
{
return _sz == 0;
}
template<class T>
void Stack<T>::Dislplay ()
{
for(int i = 0;i<_sz ;i++)
{
cout<<_a[i]<<" ";
}
cout<<endl;
}
//Maze.h
#pragma once
#include"stack.h"
#define N 10
void InitMaze(int *m) //从文件中读取数据到数组Maze中
{
FILE* fout = fopen("Maze.txt","r");
for(int i = 0; i < N;i++)
{
for(int j = 0; j< N ;)
{
char value = fgetc(fout);
if(value == 32|| value == 10)
continue;
m[i*N+j] = value - '0';
++j;
}
}
}
struct Pos
{
int _row;
int _col;
};
bool CheckPos(int row,int col,Pos p,int *m)//只有当数据为0的时候才考虑上下左右
{
if((p._row >= 0) &&(p._row < row)&&(p._col >= 0)&&(p._col < col)&&(m[p._row * N+ p._col]==0))
return true;
return false;
}
bool Through(int row,int col,Pos next)
{
if((next._row == row-1)||(next._col == col-1))
return true;
return false;
}
bool GetPath(int row,int col,int* m,Stack<Pos>& s,Pos enter)
{
s.Push (enter);
m[enter._row * N+enter._col ] = 2;
while(!s.Empty ())
{
Pos cur = s.Top ();//cur为最新压入栈中的数据,栈顶的元素就是迷宫目前能走的最后一步
Pos next = cur;//是以当前节点为中心进行上下左右节点测试的坐标变量
//上
next._row = next._row -1;//next就是坐标,栈存放的就是数组的坐标,当路径被封死,就要释放栈顶,**每当pop()后**,next要在该节点(此处不是pop()的节点)进行上下左右的分析,来判断是否有下一个可以走的节点,若没有,则继续pop(),不断的往该节点的上一个节点走,**这就是回溯**。直到某一个尾节点的上下左右有通路,再从新进行探索。
//回到最前面的问题:压栈的是数组元素的坐标,当栈被释放,因为next发生改变。所以m[next._row *N+next._col ]就成为了上一个节点,所以当我释放栈的时候,当前路径的尾节点能够变为上一个节点,从而使得上一个节点成为了新路径的尾节点
if(CheckPos(row,col,next,m))
{
s.Push (next);
m[next._row *N+next._col ]=2;
continue;
}
next._row = next._row +1;
next._row = next._row +1; //下
if(CheckPos(row,col,next,m))
{
s.Push (next);
m[next._row *N+next._col ]=2;
continue;
}
next._row = next._row -1;
next._col = next._col -1; //左
if(CheckPos(row,col,next,m))
{
s.Push (next);
m[next._row *N+next._col ]=2;
continue;
}
next._col = next._col +1;
next._col = next._col +1; //右
if(CheckPos(row,col,next,m))
{
s.Push (next);
m[next._row *N+next._col ]=2;
continue;
}
next._col = next._col -1;
if(Through(row,col,next))
return true;
s.Pop (); //当上下左右都无法走的时候
}
return false;
}
void PrintMaze(int* m)
{
for(int i = 0; i < N;i++)
{
for(int j = 0; j< N ;j++)
{
cout<<m[i*N+j]<<" ";
}
cout<<endl;
}
cout<<endl;
}
//Maze.cpp
#include"stack.h"
#include"Maze.h"
using namespace std;
void test()
{
Stack<int> s1;
s1.Push (1);
s1.Push (2);
s1.Push (3);
s1.Push (4);
s1.Push (5);
s1.Dislplay ();
cout<<s1.Empty() <<endl;
cout<<s1.Top()<<endl;
s1.Pop ();
s1.Dislplay ();
}
void MazeTest()
{
Stack<Pos> s1;
Pos e ;
e._row = 1;
e._col = 0;
int maze[N][N];
InitMaze((int*)maze);
PrintMaze((int*)maze);
GetPath(N,N,(int*)maze,s1,e);
PrintMaze((int*)maze);
}
int main()
{
//test();
MazeTest();
return 0;
}