/*
深度优先搜索的实现:
关于深度优先遍历,找不到最短路径,暂时未作分析,容后补上,以作记录
补充如下:举例如迷宫问题,都是遍历,譬如深度优先遍历、广度优先遍历。但深度优先可以最快速度找到出口,而广度优先遍历花的时间则更多;
但深度优先遍历,不一定找到最优(最短)路径,而广度优先遍历则一定能找到最短优先路径(加入有的话)。
从代码分析理解,深度优先遍历,因为使用了栈的后进先出结构,注定是做一根筋式的查找,不撞南墙不回头。而且,可能会把所有的路径都给走一遍(这是基于遍历的先后方向,如下代码所示)。
相反,广度优先遍历,因为使用了队列的先进先出结构,所有有分叉的结点,都遵循天女散花式,齐头并进的遍历。最终,某个方向的遍历,最先找到出口。因为所有分叉都是齐头并进式的遍历,则最先找到出口的,就是最短路径(但,可能不是唯一的最短路径)。
网上另一种标识图块状态的做法没看明白,此处借鉴了 linxu c编成 一站式学习的编码,纯属学习,在此作声明
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct __ElemType
{
int y;
int x;
}ElemType;
typedef struct __stackInfo
{
ElemType *pData;
unsigned int top;
unsigned int capacity;
} stackInfo;
/* 初始化 */
int initStack(stackInfo **ppS, unsigned int size)
{
if (NULL == ppS)
{
printf("ppNewStack point address is not exist\n");
return -1;
}
stackInfo *pNewStack = (stackInfo *)malloc(sizeof(stackInfo));
if (NULL == pNewStack)
{
printf("ppNewStack malloc fail\n");
return -1;
}
pNewStack->pData = (ElemType *)malloc(sizeof(ElemType)*size);
if (NULL == pNewStack->pData)
{
printf("ppNewStack databuf malloc fail\n");
/* 前面几篇代码就少了这里,务必要小心,记个坑: 一旦直接推出,则泄漏内存pNewStack */
free(pNewStack);
return -1;
}
pNewStack->capacity = size;
pNewStack->top = 0;
*ppS = pNewStack;
return 0;
}
/* 入栈 */
int pushStack(stackInfo *pS, ElemType *val)
{
if (NULL == pS)
{
printf("pStack point NULL\n");
return -1;
}
if (pS->capacity == pS->top)
{
printf("pStack full\n");
return -1;
}
memcpy(&pS->pData[pS->top], val, sizeof(ElemType));
pS->top++;
return 0;
}
/* 出栈 */
int popStack(stackInfo *pS, ElemType *val)
{
if ((NULL == pS) || (NULL == val))
{
printf("pStack point NULL or val point NULL\n");
return -1;
}
if (pS->top <= 0)
{
printf("pStack empty\n");
return -1;
}
pS->top--;
memcpy(val, &pS->pData[pS->top], sizeof(ElemType));
return 0;
}
/* 获取栈顶数据 */
int topStack(stackInfo *pS, ElemType *val)
{
if ((NULL == pS) || (NULL == val))
{
printf("pStack point NULL or val point NULL\n");
return -1;
}
if (0 >= pS->top)
{
printf("pStack empty\n");
return -1;
}
memcpy(val, &pS->pData[pS->top - 1], sizeof(ElemType));
return 0;
}
/* 计算栈中有效数据长度 */
int lengthOfStack(stackInfo *pS, unsigned int *val)
{
if ((NULL == pS) || (NULL == val))
{
printf("pStack point NULL or val point NULL\n");
return -1;
}
*val = pS->top;
return 0;
}
/* 清空栈 */
int emptyStack(stackInfo *pS)
{
if (NULL == pS)
{
printf("pStack point NULL\n");
return -1;
}
while(pS->top)
{
/* 小技巧:如果赋值为0即0,如果赋值为FF,因16、32位平台的区别,鉴于可移植性考虑,赋值为0按位取反 */
pS->top--;
}
return 0;
}
/* 销毁栈 */
int destoryStack(stackInfo **ppS)
{
if (NULL == ppS)
{
printf("pStack point address is not exist\n");
return -1;
}
if (NULL == *ppS)
{
printf("pStack point NULL\n");
return -1;
}
emptyStack(*ppS);
/* 关注点:1、两块动态内存需释放 2、注意释放的先后顺序 */
while(1)
free((*ppS)->pData);
free(*ppS);
return 0;
}
/* 拷贝栈
int copyStackElem(stackInfo *pSrcStack, stackInfo *pDestStack)
{
if ((NULL == pSrcStack) || (NULL == pDestStack))
{
printf("copyStack pSrcStack or pDestStack point NULL\n");
return -1;
}
pDestStack->top = pSrcStack->top;
for (int i=0; i<pSrcStack->top; i++)
{
memcpy(&pDestStack->pData[i], &pSrcStack->pData[i], sizeof(ElemType));
}
return 0;
} */
/* 入口 */
ElemType currAddr = {0, 0};
/* 下一步 */
ElemType nextAddr = {0, 0};
/* 出口 */
ElemType escapeAddr = {4, 4};
/* 最大路标 */
ElemType maxWayAddr = {5, 5};
/* 最小路标 */
ElemType minWayAddr = {0, 0};
/* 迷宫:1为墙壁,0为路 */
int maze[5][5]=
{
{0, 1, 0, 0, 0},
{0, 1, 0, 1, 0},
{0, 0, 0, 0, 0},
{0, 1, 1, 1, 0},
{0, 0, 0, 1, 0},
};
ElemType preDecessor[5][5] =
{
{{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}},
{{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}},
{{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}},
{{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}},
{{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}},
};
/* 更新一步 */
int visit(stackInfo *pS, ElemType *pCurrAddr, ElemType *pNextAddr)
{
maze[pNextAddr->y][pNextAddr->x] = 2;
preDecessor[pNextAddr->y][pNextAddr->x].x = pCurrAddr->x;
preDecessor[pNextAddr->y][pNextAddr->x].y = pCurrAddr->y;
pushStack(pS, pNextAddr);
return 0;
}
/* 测试入口 */
int main(void)
{
stackInfo *pNewStack = NULL;
initStack(&pNewStack, 100);
maze[currAddr.x][currAddr.y] = 2;
pushStack(pNewStack, &currAddr);
/* 保存每一步路径,有空闲空间可保存 */
while(pNewStack->top != pNewStack->capacity)
{
popStack(pNewStack, &currAddr);
if ( currAddr.x == escapeAddr.x
&& currAddr.y == escapeAddr.y)
{
break;
}
if ( currAddr.x + 1 < maxWayAddr.x
&& maze[currAddr.y][currAddr.x + 1] == 0)
{
nextAddr.x = currAddr.x + 1;
nextAddr.y = currAddr.y;
visit(pNewStack, &currAddr, &nextAddr);
}
if ( currAddr.y + 1 < maxWayAddr.y
&& maze[currAddr.y + 1][currAddr.x] == 0)
{
nextAddr.x = currAddr.x;
nextAddr.y = currAddr.y + 1;
visit(pNewStack, &currAddr, &nextAddr);
}
if ( currAddr.x - 1 >= minWayAddr.x
&& maze[currAddr.y][currAddr.x - 1] == 0)
{
nextAddr.x = currAddr.x - 1;
nextAddr.y = currAddr.y;
visit(pNewStack, &currAddr, &nextAddr);
}
if ( currAddr.y - 1 >= minWayAddr.y
&& maze[currAddr.y - 1][currAddr.x] == 0)
{
nextAddr.x = currAddr.x;
nextAddr.y = currAddr.y - 1;
visit(pNewStack, &currAddr, &nextAddr);
}
printf("print current position\n");
}
if ( currAddr.x == escapeAddr.x
&& currAddr.y == escapeAddr.y)
{
printf("(%d, %d)\n", currAddr.y, currAddr.x);
while(preDecessor[currAddr.y][currAddr.x].y != -1)
{
currAddr = preDecessor[currAddr.y][currAddr.x];
printf("(%d, %d)\n", currAddr.y, currAddr.x);
}
}
else
{
printf("no find way\n");
}
return 0;
}