棧的定義

棧是一種只能在一端進行插入或刪除操作的線性表 表中允許進行插入、刪除操作的一端稱為棧頂(top)表的另一端稱為棧底(bottom)音榜。當棧中沒有數據元素時稱為空棧 棧的插入操作通常稱為進棧入棧(push),棧的刪除操作通常稱為出棧退棧(pop)。

棧的順序存儲結構及其基本運算的實現(xiàn)

采用順序結構存儲的棧稱為順序棧

typedef struct {
    ElemType data[MaxSize];
    int top;
}SqStack;
  1. 初始化棧
void InitStack(SqStack *&s)
{
    s = (SqStack*)malloc(sizeof(SqStack));
    s->top = -1;
}
  1. 銷毀棧
void DestroyStack(SqStack *&s)
{
    free(s);
}
  1. 判斷棧是否為空
bool StackEmpty(SqStack *s)
{
    return(s->top == -1);
}
  1. 進棧
bool Push(SqStack*&s, ElemType e)
{
    if (s->top == MaxSize - 1)
        return false;
    s->top++;
    s->data[s->top] = e;
    return true;
}
  1. 出棧
bool Pop(SqStack*&s, ElemType &e)
{
    if (s->top == -1)
        return false;
    e = s->data[s->top];
    s->top--;
    return true;
}
  1. 取棧頂元素
bool GetTop(SqStack *s, ElemType &e)
{
    if (s->top == -1)
        return false;
    e = s->data[s->top];
    return true;
}
棧的鏈式存儲結構及其基本運算的實現(xiàn)

采用鏈式存儲結構的棧稱為鏈棧

typedef struct linknode
{
    ElemType data;
    struct linknode *next;
}LinkStNode;
  1. 初始化棧
void InitStack(LinkStNode *&s)
{
    s = (LinkStNode*)malloc(sizeof(LinkStNode));
    s->next = NULL;
}
  1. 銷毀棧
void DestroyStack(LinkStNode *&s)
{
    LinkStNode *pre = s,*p=s->next;
    while (p != NULL)
    {
        free(pre);
        pre = p;
        p = pre->next;
    }
    free(pre);
}
  1. 判斷棧是否為空
bool StackEmpty(LinkStNode *s)
{
    return(s->next = NULL);
}
  1. 進棧
void Push(LinkStNode *&s, ElemType e)
{
    LinkStNode *p;
    p = (LinkStNode*)malloc(sizeof(LinkStNode));
    p->data = e;
    p->next = s->next;
    s->next = p;
}
  1. 出棧
bool Pop(LinkStNode *&s, ElemType &e)
{
    LinkStNode *p;
    if (s->next == NULL)
        return false;
    e = s->data;
    p = s->next;
    s->next = p->next;
    free(p);
    return true;
}
  1. 取棧頂元素
bool GetTop(LinkStNode *s, ElemType &e)
{
    if (s->next == NULL)
        return false;
    e = s->data;
    return true;
}
求解迷宮問題

問題描述

給定一個(M , N ) 的迷宮圖捧弃,求一條從指定入口到出口的迷宮路徑赠叼。假設一個迷宮圖如下圖所示,其中的每個方塊用空白表示通道塔橡,用陰影表示障礙物梅割。一般情況下,所求迷宮路徑是簡單路徑葛家,即在求得的迷宮路徑上不會重復出現(xiàn)同一方塊户辞。一個迷宮圖的迷宮路徑可能有多條,這里僅僅考慮用棧求一條從指定入口到出口的迷宮路徑癞谒。

數據組織

為了表示迷宮底燎,設置一個數組mg刃榨,其中每個元素表示一個方塊的狀態(tài),為0時表示對應的方塊是通道双仍,為1時表示對應方塊時障礙物枢希。為了運算方便,一般在迷宮的外圍加一條圍墻朱沃。

#define M 8
#define N 8
int mg[M+2][N+2]=
{
    {1,1,1,1,1,1,1,1,1,1},{1,0,0,1,0,0,0,1,0,1},
    {1,0,0,1,0,0,0,1,0,1},{1,0,0,0,0,1,1,0,0,1},
    {1,0,1,1,1,0,0,0,0,1},{1,0,0,0,1,0,0,0,0,1},
    {1,0,1,0,0,0,1,0,0,1},{1,0,1,1,1,0,1,1,0,1},
    {1,1,0,0,0,0,0,0,0,1},{1,1,1,1,1,1,1,1,1,1}
};

在算法中用到的棧采用順序棧存儲結構

typedef struct{
    int i;//當前方塊的行號
    int j;//當前方塊的列號
    int di;//di是下一相鄰可走方位的方位號
}Box;

typedef struct{
    Box data[MaxSize];
    int top;
}StType;

設計運算算法

  • 對于迷宮中的每個方塊苞轿,有上、下逗物、左搬卒、右 4 個方塊相鄰,規(guī)定上方方塊為0翎卓,并按順時針方向遞增標號契邀。
  • 求解迷宮問題采用的算法思想為“窮舉法”。即從入口出發(fā)失暴,按方位0到方位3的次序試探相鄰的方塊坯门,一旦找到一個可走的相鄰方塊就繼續(xù)走下去,并記下所走的方位逗扒。若沒有相鄰的可走方塊古戴,則沿原路退回到前一個方塊。
  • 若一個非出口方塊是可走的矩肩,將它進棧允瞧,如果找到某個方位 的相鄰方塊是可走的,則將棧頂方塊的方位 di 置為d蛮拔。
  • 在算法上應保證試探的相鄰可走方塊不是已走路徑上的方塊,因此在一個方塊進棧后將對應的 mg 數組元素值改為 -1 當退棧時將其恢復為 0
將入口(xi,yi)進棧(其初始方位設置為-1)
mg[xi][yi]=-1;
while(棧不為空)
{
    取棧頂方塊(i,j,di);
    if((i,j)是出口(xi,yi))
    {
        輸出棧中的全部方塊構成一條迷宮路徑
        return true;
    }
    查找(i,j,di)的下一個相鄰可走方塊;
    if(找到一個相鄰可走方塊)
    {
        該方塊為(i1,j1),對應方位d;
        將棧頂方塊的di設置為d;
        (i1,j1,-1)進棧;
        mg[i1][j1]=-1;
    }
    if(沒有找到(i,j,di)的任何相鄰可走方塊)
    {
        將(i,j,di)出棧:
        mg[i][j]=0;
    }
}
return false; //沒有找到迷宮路徑
bool mgpath(int xi,int yi,int xe,int ye)
{
    Box path[MaxSize],e;
    int i,j,di,i1,j1,k;
    bool find;
    StType*st;
    InitStack(st);
    e.i=xi;e.j=yi;e.di=-1;
    Push(st,e);
    mg[xi][yi]=-1;
    while(!StackEmpty(st))
    {
        GetTop(st,e);
        i=e.i;j=e.j;di=e.di;
        if(i==xe&&j==ye)
        {
            printf("一條迷宮路徑如下:\n");
            k=0;
            while(!StackEmpty(st))
            {
                Pop(st,e);
                path[k++]=e;
            }
            while(k>=1)
            {
                k--;
                printf("\t(%d,%d)",path[k].i,path[k].j);
                if((k+2)%5==0)
                    printf("\n");
            }
            DestroyStack(st);
            return true;
        }
        find=false;
        while(di<4&&!find)
        {
            di++;
            switch(di)
            {
                case 0: i1=i-1;j1=j;break;
                case 1: i1=i;j1=j+1;break;
                case 2: i1=i+1;j1=j;break;
                case 3: i1=i;j1=j-1;break;
            }
            if(mg[i1][j1]==0) find=true;
        }
        if(find)
        {
            st->data[st->top].di=di;
            e.i=i1;e.j=j1;e.di=-1;
            Push(st,e);
            mg[i1][j1]=-1;
        }
        else
        {
            Pop(st,e);
            mg[e.i][e.j]=0;
        }
    }
    DestroyStack(st);
    return false;
}

設計求解程序

int main(){
    if(!mppath(1,1,M,N))
        printf("該迷宮問題沒有解");
    return 0;
}

問題進階

在上述的過程中痹升,我們只能找到一條路徑建炫。可是疼蛾,往往我們需要找出最短路徑肛跌,對于棧而言,我們可以通過找出所有的路徑察郁,從而確定最短的路徑衍慎。由上述的分析可知,回溯的關鍵是 di 值要找出所有的路徑皮钠,直接退棧即可稳捆,并將該方塊對應的mg數組置為0,由于回溯過后的那個方塊保存了信息就可以實現(xiàn)窮舉出所有的路徑麦轰。

bool mgpath(int xi, int yi, int xe, int ye)
{
    Box path[MaxSize], e;
    int i, j, di, i1, j1, k;
    int num=0;//用來判斷是否有路徑輸出
    bool find;
    StType*st;
    InitStack(st);
    e.i = xi; e.j = yi; e.di = -1;
    Push(st, e);
    mg[xi][yi] = -1;
    while (!StackEmpty(st))
    {
        GetTop(st, e);
        i = e.i; j = e.j; di = e.di;
        if (i == xe && j == ye)
        {
            num++;
            printf("\n一條迷宮路徑如下:\n");
            k = 0;
            int n = st->top;//由于要回溯需要棧的信息不能采用退棧的方式
            while (n!=-1)
            {
                e = st->data[n--];
                path[k++] = e;
            }
            while (k >= 1)
            {
                k--;
                printf("\t(%d,%d)", path[k].i, path[k].j);
                if ((k + 2) % 5 == 0)
                    printf("\n");
            }
            mg[i][j] = 0; //設置出口狀態(tài)為0
            Pop(st, e); //回溯
            mg[e.i][e.j] = 0; //設置其狀態(tài)為0
            i = e.i; j = e.j; di = e.di; //將i和j置為當前方塊的值
        }
        find = false;
        while (di < 4 && !find)
        {
            di++;
            switch (di)
            {
            case 0: i1 = i - 1; j1 = j; break;
            case 1: i1 = i; j1 = j + 1; break;
            case 2: i1 = i + 1; j1 = j; break;
            case 3: i1 = i; j1 = j - 1; break;
            }
            if (mg[i1][j1] == 0) find = true;
        }
        if (find)
        {
            st->data[st->top].di = di;
            e.i = i1; e.j = j1; e.di = -1;
            Push(st, e);
            mg[i1][j1] = -1;
        }
        else
        {
            Pop(st, e);
            mg[e.i][e.j] = 0;
        }
    }
    DestroyStack(st);
    if(num>0) return true;
    return false;
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末乔夯,一起剝皮案震驚了整個濱河市砖织,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌末荐,老刑警劉巖侧纯,帶你破解...
    沈念sama閱讀 216,843評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異甲脏,居然都是意外死亡眶熬,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評論 3 392
  • 文/潘曉璐 我一進店門块请,熙熙樓的掌柜王于貴愁眉苦臉地迎上來娜氏,“玉大人,你說我怎么就攤上這事负乡‰拱祝” “怎么了?”我有些...
    開封第一講書人閱讀 163,187評論 0 353
  • 文/不壞的土叔 我叫張陵抖棘,是天一觀的道長茂腥。 經常有香客問我,道長切省,這世上最難降的妖魔是什么最岗? 我笑而不...
    開封第一講書人閱讀 58,264評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮朝捆,結果婚禮上般渡,老公的妹妹穿的比我還像新娘。我一直安慰自己芙盘,他們只是感情好驯用,可當我...
    茶點故事閱讀 67,289評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著儒老,像睡著了一般蝴乔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上驮樊,一...
    開封第一講書人閱讀 51,231評論 1 299
  • 那天薇正,我揣著相機與錄音,去河邊找鬼囚衔。 笑死挖腰,一個胖子當著我的面吹牛,可吹牛的內容都是我干的练湿。 我是一名探鬼主播猴仑,決...
    沈念sama閱讀 40,116評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼鞠鲜!你這毒婦竟也來了宁脊?” 一聲冷哼從身側響起断国,我...
    開封第一講書人閱讀 38,945評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎榆苞,沒想到半個月后稳衬,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,367評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡坐漏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,581評論 2 333
  • 正文 我和宋清朗相戀三年薄疚,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赊琳。...
    茶點故事閱讀 39,754評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡街夭,死狀恐怖,靈堂內的尸體忽然破棺而出躏筏,到底是詐尸還是另有隱情板丽,我是刑警寧澤,帶...
    沈念sama閱讀 35,458評論 5 344
  • 正文 年R本政府宣布趁尼,位于F島的核電站埃碱,受9級特大地震影響,放射性物質發(fā)生泄漏酥泞。R本人自食惡果不足惜砚殿,卻給世界環(huán)境...
    茶點故事閱讀 41,068評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望芝囤。 院中可真熱鬧似炎,春花似錦、人聲如沸悯姊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,692評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽悯许。三九已至传睹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間岸晦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,842評論 1 269
  • 我被黑心中介騙來泰國打工睛藻, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留启上,地道東北人。 一個月前我還...
    沈念sama閱讀 47,797評論 2 369
  • 正文 我出身青樓店印,卻偏偏與公主長得像冈在,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子按摘,可洞房花燭夜當晚...
    茶點故事閱讀 44,654評論 2 354

推薦閱讀更多精彩內容