采用回溯和递归两种算法实现简单迷宫(单通路迷宫)

回溯法:对一个包含有很多个结点,每个节点有若干个搜索分支的问题,把原问题分解为若干个子问题求解的算法。当搜索到某个结点发现无法再继续搜索下去时,就让搜索过程回溯(回退)到该节点的前一个节点,继续搜索该节点外的分支;如果发现该节点无法再搜索下去,就让搜索过程回溯到这个节点的前一个节点继续这样的搜索过程;这样的搜索过程一直进行到搜索到问题的解或者搜索完了全部可搜索分支依旧没有解存在为止。

举一个简单迷宫的例子
0 0 0 0 0 0
0 0 1 0 0 0
0 0 1 0 0 0
0 0 1 1 1 0
0 0 1 0 1 1
0 0 1 0 0 0
其中,0代表走不通,1代表能走通。
下面分别采用回溯法和递归法实现该迷宫。
1.【回溯法】

  • 顺序栈的基本运算(保存在Stack.h中)
#include
#include
#include
#include


typedef struct Position
{
    int _x;
    int _y;
}Position;


typedef Position DataType;
//typedef int DataType;
#define MAX_SIZE 100


typedef struct Stack
{
    DataType array[MAX_SIZE];
    int top;//栈顶元素的下标
}Stack;

void StackInit(Stack* s);
void StackPush(Stack* s, DataType data);
void StackPop(Stack* s);
DataType StackTop(Stack* s);
int StackEmpty(Stack* s);

void StackInit(Stack* s)//栈初始化
{
    s->top = 0;
}

int StackEmpty(Stack* s)//判断栈是否为空
{
    if (s->top == 0)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

void StackPush(Stack* s, DataType data)//入栈
{
    if (s->top >= MAX_SIZE)
    {
        printf("栈已满,放不了了!\n");
        return;
    }
    else
    {
        s->array[s->top] = data;
        s->top++;
        return;
    }
}

void StackPop(Stack* s)//出栈
{
    if (s->top == 0)
    {
        printf("栈已经没有元素了!\n");
    }
    else
    {
        s->top--;

    }
}

DataType StackTop(Stack* s)//获取栈顶元素
{
    assert(!StackEmpty(s));
    return s->array[(s->top)-1];
}

void Print(Stack* s)//打印栈
{
    int i = 0;
    for (i =```````
(s->top) - 1; i >= 0; i--)
    {
        printf("%d\n", s->array[i]);
    }
    printf("\n");
}
  • 迷宫的回溯算法
#pragma once
#include
#include"Stack.h"

//设置迷宫的行和列
#define MAX_ROW 6
#define MAX_COL 6

typedef struct Maze
{
    int _map[MAX_ROW][MAX_COL];
}Maze;

void InitMap(Maze* m, int map[MAX_ROW][MAX_COL]);
void PrintMap(Maze*m);
int IsValidEnter(Maze* m, Position enter);
int IsExit(Maze* m, Position cur, Position enter);
int IsPass(Maze*m, Position next);
void PassMaze(Maze* m, Position enter, Stack* s);

void InitMap(Maze* m, int map[MAX_ROW][MAX_COL])//对迷宫进行初始化
{
    int i = 0;
    int j = 0;
    if (NULL == m)
    {
        return;
    }
    for (i = 0; i < MAX_ROW; ++i)
    {
        for (j = 0; j < MAX_COL; ++j)
        {
            m->_map[i][j] = map[i][j];
        }
    }
}

void PrintMap(Maze*m)//打印迷宫
{
    int i = 0;
    int j = 0;
    if (NULL == m)
    {
        return;
    }
    for (i = 0; i < MAX_ROW; ++i)
    {
        for (j = 0; j < MAX_COL; ++j)
        {
            printf("%d ", m->_map[i][j]);
        }
        printf("\n");
    }
}


int IsValidEnter(Maze* m, Position enter)//检测入口是否有效
{
    if (NULL == m)
    {
        return 0;
    }
    else
    {
        return 1 == m->_map[enter._x][enter._y];//坐标为1即为有效入口
    }
}

int IsExit(Maze* m, Position cur, Position enter)//判断当前位置是否为出口
{
    if (cur._x == enter._x&&cur._y == enter._y)//若当前位置的坐标和入口一样,则无效
    {
        return 0;
    }
    if (0 == cur._x || MAX_ROW - 1 == cur._x || 0 == cur._y || MAX_COL - 1 == cur._y)//若当前位置在边界则为出口
    {
        return 1;
    }
    return 0;
}

int IsPass(Maze*m, Position next)//判断是否可以走通
{
    if (NULL == m)
    {
        return 0;
    }
    return 1 == m->_map[next._x][next._y];//坐标为1则可以走通
}


void PassMaze(Maze* m, Position enter, Stack* s)//走迷宫
{
    Position next;
    //检测入口是否有效,若有效则入栈,无效则返回
    if (!IsValidEnter(m, enter))
    {
        printf("迷宫入口有误\n");
        return;
    }
    else
    {
        StackPush(s, enter);
    }
    while (!StackEmpty(s))
    {
        Position cur = StackTop(s);//取栈顶位置,标记为当前位置
        m->_map[cur._x][cur._y] = 2;//将当前位置标记为2,走当前位置并判断是否为出口
        if (IsExit(m, cur,enter))//是出口则返回,不是出口则判断上、左、右、下四个方向那个方向可以走通,能走通则入栈,重复该过程
        {
            return;
        }
        else
        {
            //上
            next = cur;
            next._x -= 1;
            if (IsPass(m, next))
            {
                StackPush(s, next);
                continue;
            }
            //左
            next = cur;
            next._y -= 1;
            if (IsPass(m, next))
            {
                StackPush(s, next);
                continue;
            }
            //右
            next = cur;
            next._y += 1;
            if (IsPass(m, next))
            {
                StackPush(s, next);
                continue;
            }
            //下
            next = cur;
            next._x += 1;
            if (IsPass(m, next))
            {
                StackPush(s, next);
                continue;
            }
            //都走不通,标记为3,并退回到上一步(出栈)
            m->_map[cur._x][cur._y] = 3;
            StackPop(s);
            continue;
        }
    }
}
  • 检测
void TestMap()
{
    Maze m;
    Position enter;
    Stack s;
    int map[MAX_ROW][MAX_COL] = {
        { 0, 0, 0, 0, 0, 0 },
        { 0, 0, 1, 0, 0, 0 },
        { 0, 0, 1, 0, 0, 0 },
        { 0, 0, 1, 1, 1, 0 },
        { 0, 0, 1, 0, 1, 1 },
        { 0, 0, 1, 0, 0, 0 } };
    InitMap(&m, map);
    PrintMap(&m);
    printf("\n");

    StackInit(&s);
    enter._x = 5;
    enter._y = 2;
    PassMaze(&m, enter,&s);
    PrintMap(&m);
}

2.【递归】
递归法不需要使用栈,故不用再引用栈的头文件,除了走迷宫函数需要改变以外,其余部分都无需改变。

int PassMaze(Maze* m, Position enter,Position cur)
{
    Position next;
    /*if (!IsValidEnter(m, enter))
    {
        printf("迷宫入口有误\n");
    }*/
    if (1 == m->_map[cur._x][cur._y])
    {
        m->_map[cur._x][cur._y] = 2;
        if (IsExit(m, cur, enter))
        {
            return 1;
        }
        //上
        next = cur;
        next._x -= 1;
        if (PassMaze(m, enter, next))
            return 1;

        //左
        next = cur;
        next._y -= 1;
        if (PassMaze(m, enter, next))
            return 1;

        //右
        next = cur;
        next._y += 1;
        if (PassMaze(m, enter, next))
            return 1;

        //下
        next = cur;
        next._x += 1;
        if (PassMaze(m, enter, next))
            return 1;

        //都走不通
        m->_map[cur._x][cur._y] = 3;
    }
    return 0;
}

你可能感兴趣的:(数据结构)