數據結構---多出口迷宮找出一條最短路徑

前面我們實現了基礎版本的迷宮求解,只有一條路徑。現在如果有多個出口,我們該如何去找到一條最短的路徑。

我們先來思考一下我們是如何在一個數組裏找最小值的?
有下面一個數組:
這裏寫圖片描述
我們可以先把第一個數設爲最小值,然後遍歷數組,拿它和後面的元素進行比較,把兩個數中較小的賦給min,直到遍歷完整個數組,min中就是數組中的最小值。

同樣的,找最短路徑也是一樣的思路。我們可以定義兩個棧,一個cur_path保存當前路徑,一個short_path保存最短路徑,每次找到一條路徑,將它保存在cur_path裏,並和short_path進行比較,將兩條路徑中較短的路徑保存在short_path中,最後打印short_path的內容。
這裏寫圖片描述
可以看出,黃色圈出來的就是最短路徑。
步驟也是和前面大體一致,只是加了一個當前路徑cur_path和最短路徑short_path的比較,代碼中有詳解,大家可以參考一下.
話不多說,直接上代碼:

//先對迷宮初始化
void MazeShortPathInit(Maze* maze)
{
    int map[MAX_ROW][MAX_COL] = {
        {0,1,0,0,0,0},
        {0,1,1,1,0,0},
        {0,1,0,1,0,0},
        {1,1,0,1,1,1},  
        {0,1,1,0,0,0},
        {0,0,1,0,0,0},
    };
    size_t i = 0;
    for( ;i < MAX_ROW;i++)
    {
        size_t j = 0;
        for( ;j < MAX_COL;j++)
        {
            maze->map[i][j] = map[i][j];
        }
    }
    return;
}
//遍歷所有的路徑,然後從其中找出一條最短路徑
//實現遞歸版本
void GetShortPath(Maze* maze,Point entry)
{
    //保存着當前路徑
    SeqStack cur_path;
    //保存最短路徑
    SeqStack short_path;

    SeqStackInit(&cur_path);
    SeqStackInit(&short_path);
    _GetShortPath(maze,entry,entry,&cur_path,&short_path);
    //打印棧裏面的內容(通常意義下,棧是不允許遍歷的,但是這裏僅僅用於調試)
    SeqStackPrintDebug(&short_path,"最短路徑是:");
}

void _GetShortPath(Maze* maze,Point cur,Point entry,SeqStack* cur_path,SeqStack* short_path)
{
    //1.判斷當前點是否能落腳
    if( !CanStay(maze,cur))
    {
        return;
    }
    //2.如果能落腳,標記當前點並且入棧到cur_path
    Mark(maze,cur);
    SeqStackPush(cur_path,cur);
    //3.判斷當前點是否爲出口
    if(IsExit(maze,cur,entry))
    {
    //  如果是出口,說明找到了一條路徑,拿當前路徑和short_path中的路徑比較
    //  a)如果當前路徑比short_path中路徑短或者short_path爲空,就用當前路徑替換short_path
    //  b)如果當前路徑沒有short_path中路徑短,嘗試去找其他的路經(進行回溯),出棧cur_path的棧頂元素
        printf("找到了一條路徑\n");
        if(cur_path->size < short_path->size || short_path->size == 0)
        {
            SeqStackAssgin(cur_path,short_path);
        }
        SeqStackPop(cur_path);
        return;
    }
    //4.如果當前點不是出口,嘗試順時針去探測其他四個方向
    Point up = cur;
    up.ROW -= 1;
    _GetShortPath(maze,up,entry,cur_path,short_path);

    Point right = cur;
    right.COL += 1;
    _GetShortPath(maze,right,entry,cur_path,short_path);

    Point down = cur;
    down.ROW += 1;
    _GetShortPath(maze,down,entry,cur_path,short_path);

    Point left = cur;
    left.COL -= 1;
    _GetShortPath(maze,left,entry,cur_path,short_path);
    //5.如果四個方向都遞歸的探測完了,就可以進行出棧(cur_path),回溯到上一個點
    SeqStackPop(cur_path);
}

這裏用到的輔助函數打印棧信息SeqStackPrintDebug()和棧替換SeqStackAssgin()如下,而判斷當前點能不能落腳CanStay()函數,判斷是否是出口IsExit()函數和標記Mark()函數在之前博客中(基礎版迷宮求解)寫過,這裏就不做具體介紹。

void SeqStackAssgin(SeqStack* from,SeqStack* to)
{
    //爲了保證to裏面的內存能夠足夠的容納from中的元素
    //採用以下策略:
    //1.釋放to中的原有內存
    SeqStackDestroy(to);
    //2.根據from中的元素個數,確定內存申請的大小
    to->size = from->size;
    to->capacity = from->capacity;
    //3.給to申請一個足夠的內存
    to->data = (SeqStackType*)malloc(to->capacity*sizeof(SeqStackType));
    //4.最後進行數據的拷貝
    size_t i = 0;
    for( ;i < from->size;i++)
    {
        to->data[i] = from->data[i];
    }
    return;
}
void SeqStackPrintDebug(SeqStack* stack,char* msg)
{
    printf("[%s]\n",msg);
    size_t i = 0;
    for( ;i < stack->size;i++)
    {
        printf("(%d,%d)\n",stack->data[i].ROW,stack->data[i].COL);
    }
    printf("\n");
}

結果如下圖:
這裏寫圖片描述

發佈了56 篇原創文章 · 獲贊 13 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章