栈的应用举例:迷宫求解

参考严蔚敏老师的《数据结构》栈和队列这一章的相关内容完成的

栈的定义与基本操作的实现

/* 栈的顺序存储表示 */
#define STACK_INIT_SIZE 100
#define STACKINCREMENT  10
typedef struct
{
    ElemType *base;
    ElemType *top;
    int stacksize;
}SqStack;

/* 基本操作函数 9个 */

Status InitStack(SqStack *S)
{/* 01构造一个空栈 */
    S->base = (ElemType *)malloc(STACK_INIT_SIZE * sizeof(ElemType));
    if (!S->base)
    {
        printf("存储分配失败!:InitStack()\n");
        exit(OVERFLOW);
    }
    S->top = S->base;
    S->stacksize = STACK_INIT_SIZE;
    return OK;
}

Status DestroyStack(SqStack *S)
{/* 02销毁栈S */
    free(S->base);
    free(S->top);
    S->base = NULL;
    S->top = NULL;
    S->stacksize = 0;
    return OK;
}

Status ClearStack(SqStack S)
{/* 03把S设置为空栈 */
    S.top = S.base;
    return OK;
}

Status StackEmpty(SqStack S)
{/* 04查看栈是否为空 */
    return (S.top == S.base) ? TRUE : FALSE;
}

int StackLength(SqStack S)
{/* 05查看栈长度 */
    return (S.top-S.base)/sizeof(ElemType);
}

Status GetTop(SqStack S, ElemType *e)
{/* 06获取栈顶元素 */
    if (StackEmpty(S))
    {
        return FALSE;
    }
    else
    {
        *e = *(S.top-1);
    }
}

Status Push(SqStack *S, ElemType e)
{/* 07入栈 */
    if (StackLength(*S)==S->stacksize)
    {
        ElemType *newbase;
        newbase = (ElemType *)realloc(S, (S->stacksize+STACKINCREMENT)*sizeof(ElemType));
        if(!newbase)
        {
            printf("存储分配失败!:Push()\n");
            exit(OVERFLOW);
        }
        S->base = newbase;
        S->stacksize += STACKINCREMENT;
    }
    *(S->top) = e;
    S->top++;
    return OK;
}

Status Pop(SqStack *S, ElemType *e)
{/* 08出栈 */
    if (StackEmpty(*S))
    {
        return FALSE;
    }
    else
    {
        *e = *(--S->top);
    }
    return OK;
}

Status StackTraverse(SqStack S, Status (* visit)(ElemType e))
{/* 09遍历栈中元素 */
    while (S.top != S.base)
    {
        visit(*(--S.top));
    }
    printf("\n");
    return OK;
}

cbo3-1.c

迷宫求解的算法实现

typedef struct
{
    int x;  // 行号
    int y;  // 列号
} PosType;
typedef struct
{
    int ord;        // 序号
    PosType seat;   // 坐标
     int di;     // 方向 0123代表右下左上,默认向右
} ElemType;
#include "c1.h"
#include "cbo3-1.c"

/* 迷宫求解 */

/*
 * 地图
 * '#'    墙
 * ' '    路
 * 's'    入口
 * 'e'    出口
 * '*'  当前位置
 * 'o'  走过的路
 */
int map[10][10] = {{'#', '#', '#', '#', '#', '#', '#', '#', '#', '#'},
                   {'#', ' ', ' ', '#', ' ', ' ', ' ', '#', ' ', '#'},
                   {'#', ' ', ' ', '#', ' ', ' ', ' ', '#', ' ', '#'},
                   {'#', ' ', ' ', ' ', ' ', '#', '#', ' ', ' ', '#'},
                   {'#', ' ', '#', '#', '#', ' ', ' ', ' ', ' ', '#'},
                   {'#', ' ', ' ', ' ', '#', ' ', ' ', ' ', ' ', '#'},
                   {'#', ' ', '#', ' ', ' ', ' ', '#', ' ', ' ', '#'},
                   {'#', ' ', '#', '#', '#', ' ', '#', '#', ' ', '#'},
                   {'#', '#', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '#'},
                   {'#', '#', '#', '#', '#', '#', '#', '#', '#', '#'}};


PosType start;      // 入口坐标
PosType end;        // 出口坐标
SqStack ss;         // 栈
ElemType cur, top;  // 当前位置和栈顶位置


PosType direc[4] = {{0, 1},     // 右
                    {1, 0},     // 下
                    {0, -1},    // 左
                    {-1, 0}};    // 上
                    

int step = 0;       // 走的步数

/**
 * 打印地图有的
 */
void printMap();

int pass(PosType pt)
{ /* 判断该位置是否是通路 1:通路, 0:不是通路*/
    return map[pt.x][pt.y] == ' ' ? 1 : 0;
}

int isEnd(PosType pt)
{ /* 判断该位置是否是出口 1:是 0:不是 */
    int re = 0;
    if(pt.x == end.x && pt.y == end.y) {
        re = 1;
    }
    return re;
}

void print(ElemType e, char *s)
{ /* 打印栈元素 */
    printf("%s [e.ord:%d, e.seat(%d, %d), e.di:%d]\n", s, e.ord, e.seat.x, e.seat.y, e.di);
}

void setfoot(PosType pt, int op)
{ /* 设置脚印1:设置 0:清除 */
    if (map[pt.x][pt.y]==' ' && op==1)
    { // 只有在通路上设置脚印
        map[pt.x][pt.y] = 'o';
    }
    else if (map[pt.x][pt.y]=='o' && op==0)
    { // 清除脚印
        map[pt.x][pt.y] = ' ';
    }
}

int nextDi(ElemType e, ElemType *next)
{ /* next是e位置的下一个指向 */
    if (e.di<3)
    {
        next->di = 0;
        next->seat = e.seat;
        next->seat.x += direc[e.di+1].x;
        next->seat.y += direc[e.di+1].y;
    }
    else
    {   // 无路可走
        return 0;
    }
    return 1;
}

int main()
{
    /* 设置出口入口坐标 */
    start.x = 1;
    start.y = 1;
    end.x = 8;
    end.y = 8;

    /* 初始化当前位置 */
    cur.ord = 0;
    cur.seat = start;   // 设定当前位置的初值为入口坐标
    cur.di = 0;
    InitStack(&ss);
    
    printMap();
    
    int isStep=0;
    do {
        step++;
        if(isStep)
        {
            printf("\n******按回车键查看下一步******\n");
            getchar();
            printMap();
            isStep = 0;
        }
        if (pass(cur.seat))
        { // 若当前位置是通路
            cur.ord++;
            Push(&ss, cur);          // 将当前位置入栈
            setfoot(cur.seat, 1);    // 设置脚印
            print(cur, "当前位置入栈");
            isStep = 1;
            
            GetTop(ss, &top);
            if (isEnd(cur.seat))
            {   // 该位置是出口,则结束
                printf("pass! game over!\n");
                system("pause");
                
                return 0;
            }
            else
            {
                cur.seat.y++;   // 切换当前位置的右方为新的当前位置
                printf("当前位置向右移");
            }
        }
        else
        {  // 当前位置不通
            if (!StackEmpty(ss))
            { // 栈不空
                if (nextDi(top, &cur))
                { // 栈顶位置尚有其它方向,并且设定新的当前位置为顺时针方向旋转的栈顶位置的下一邻块
                    Pop(&ss, &top);
                    top.di++;
                    Push(&ss, top); // 修改栈顶元素的di
                    printf("修改栈顶位置的di");
                }
                else
                { // 栈顶位置的四周都不通
                    Pop(&ss, &top);         // 删除栈顶位置
                    setfoot(top.seat, 0);   // 清除脚印
                    print(top, "栈顶位置出栈");
                    isStep = 1;

                    GetTop(ss, &top);
                    if(!StackEmpty(ss))
                    { // 如果栈不空,则重新测试新的栈顶位置
                        GetTop(ss, &cur);
                    }
                    else
                    { // 栈为空,无结果
                        printf("no way\n");
                        break;
                    }
                }
            }
        }
    } while (!StackEmpty(ss));
    
    system("pause");
    return 0;
}

int visit(ElemType e) {
    printf("[ord:%d\t seat:(%d, %d) di:%d]\n", e.ord, e.seat.x, e.seat.y, e.di);
}

void printMap()
{
    printf("step = %d\n", step);
    print(cur, "当前位置");
    if(!StackEmpty(ss))
    {
        print(top, "栈顶位置");
        StackTraverse(ss, visit);
    }
    int i, j;   // i代表行,j代表列
    for (i=0; i<10; i++)
    {
        for (j=0; j<10; j++)
        {
            /*
            if (cur.seat.x==i && cur.seat.y==j)
            {
                printf("%c ", '*');

            }
            else if (start.x==i && start.y==j)
            {
                printf("%c ", 's');
            }
            else if (end.x==i && end.y==j)
            {
                printf("%c ", 'e');
            }
            else
            {
                printf("%c ", map[i][j]);
            }*/
            printf("%c ", map[i][j]);
        }
        printf("\n");
    }
    printf("\n");
}

main3-3.c

用到的一个包含文件

/* c1.h (程序名) */
 #include<string.h>
 #include<ctype.h>
 #include<malloc.h> /* malloc()等 */
 #include<limits.h> /* INT_MAX等 */
 #include<stdio.h> /* EOF(=^Z或F6),NULL */
 #include<stdlib.h> /* atoi() */
 #include<io.h> /* eof() */
 #include<math.h> /* floor(),ceil(),abs() */
 #include<process.h> /* exit() */
 /* 函数结果状态代码 */
 #define TRUE 1
 #define FALSE 0
 #define OK 1
 #define ERROR 0
 #define INFEASIBLE -1
 /* #define OVERFLOW -2 因为在math.h中已定义OVERFLOW的值为3,故去掉此行 */
 typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
 typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */

c1.h
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容

  • 二、栈和队列 栈和队列都是线性结构,它们是操作受限的线性表,即它们的操作是线性表操作的子集。因此也可以用线性表在某...
    MinoyJet阅读 444评论 0 1
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,808评论 25 707
  • 本篇将尝使用canvas + wasm画一个迷宫,生成算法主要用到连通集算法,使用wasm主要是为了提升运行效率。...
    极乐君阅读 3,638评论 0 9
  • 之前在微博 @算法时空 做了一次电台,花了一个多小时谈了一下Sedgewick和Wayne所著的畅销书《算法》第4...
    算法时空阅读 6,291评论 1 39
  • 我是一粒尘埃,静静的躺在鄂尔多斯高原煤海的臂弯,看着很多默默无闻的煤矿工人辛勤劳作,陪着他们守望在这片矿山,耕作未...
    尘飞扬兮阅读 350评论 1 12