數(shù)據(jù)結(jié)構(gòu)與算法 - 棧

本文首發(fā)于 個(gè)人博客

我們都知道函數(shù)都是存放在棧上棍掐,由系統(tǒng)幫我們管理,那么棧到底是一種什么樣的數(shù)據(jù)結(jié)構(gòu)呢龄砰?他是如何管理數(shù)據(jù)的伞广? 日常開(kāi)發(fā)中我們或許并沒(méi)有直接的用上棧這種數(shù)據(jù)結(jié)構(gòu)拥知,但是它卻能幫我們解決一些很棘手的問(wèn)題,這篇文章主要分享一下個(gè)人對(duì)棧的理解以及如何用 c去實(shí)現(xiàn)一個(gè)棧的結(jié)構(gòu)态罪。本文涉及的代碼可以前往 示例代碼 處查看黎茎。

棧結(jié)構(gòu)

我們知道棧其實(shí)也是一種線性結(jié)構(gòu),接下來(lái)我們從兩種邏輯來(lái)實(shí)現(xiàn)它炉峰,順序存儲(chǔ)鏈?zhǔn)酱鎯?chǔ) 畏妖。

順序棧

順序存儲(chǔ)通常都要借助于數(shù)組,因?yàn)閿?shù)組中的數(shù)據(jù)在內(nèi)存中都是連續(xù)的疼阔,為了方便我們對(duì)于棧的查詢(xún)以及遍歷戒劫,我們加入一個(gè)指向棧頂?shù)脑?top, 那么其數(shù)據(jù)結(jié)構(gòu)應(yīng)該是這樣:

typedef int Status;
typedef int Data;

typedef struct {
    Data data[MAXSIZE];
    int top;
}Stack;

其結(jié)構(gòu)很簡(jiǎn)單半夷,用一個(gè)數(shù)組能保存棧中每個(gè)位置的數(shù)據(jù),然后用一個(gè) top 來(lái)記錄當(dāng)前棧的頂位于何處谱仪,這樣我們就能通過(guò)一系列的方法對(duì)棧進(jìn)行操作玻熙。

// 初始化空棧
Status InitStack (Stack *S) {
    S->top = -1;
    return SUCCESS;
}

// 清空棧
Status ClearStack (Stack *S) {
    S->top = -1;
    return SUCCESS;
}

// 判斷是否為空棧
bool IsEmpty(Stack S) {
    if (S.top == -1) {
        return true;
    } else {
        return false;
    }
}

// 返回棧長(zhǎng)度
int StackLength(Stack s) {
    return s.top+1;
}

// 獲取棧頂元素
Status GetStackTop(Stack S,Data *data) {
    if (S.top == -1)return ERROR;
    *data = S.data[S.top];
    return SUCCESS;
}

// 入棧
Status PushData(Stack *S,Data data) {
    if (S->top == MAXSIZE-1) return ERROR;
    int top = S->top+1;
    S->data[top] = data;
    S->top++;
    return SUCCESS;
}

// 出棧
Status Pop(Stack *S,Data *data) {
    if (S->top == -1) return ERROR;
    *data = S->data[S->top];
    S->top--;
    return SUCCESS;
}

// 從棧底到棧頂打印棧
Status PrintStack(Stack S) {
    if (S.top == -1) {
        printf("空棧 \n");
        return ERROR;
    }
    for (int i = 0; i <= S.top; i ++) {
        printf("%d--",S.data[i]);
    }
    printf("\n");
    return SUCCESS;
}

驗(yàn)證

int main(int argc, const char * argv[]) {
    // insert code here...
    Stack S;
    InitStack(&S);
    for (int i = 0; i < 10; i ++) {
        PushData(&S, i);
    }
    PrintStack(S);

    Data data;
    Pop(&S, &data);
    PrintStack(S);
    printf("出棧的數(shù)據(jù)是: %d \n",data);

    GetStackTop(S, &data);
    printf("棧頂?shù)臄?shù)據(jù)是: %d \n",data);
    return 0;
}
------------------------打印數(shù)據(jù)
棧中數(shù)據(jù)是:0--1--2--3--4--5--6--7--8--9--
棧中數(shù)據(jù)是:0--1--2--3--4--5--6--7--8--
出棧的數(shù)據(jù)是: 9 
棧頂?shù)臄?shù)據(jù)是: 8 

有幾個(gè)小細(xì)節(jié)點(diǎn)需要我們注意:

  • 線性棧的置空不用清空每個(gè)位置的數(shù)據(jù),只需要修改 top 即可
  • 返回棧的長(zhǎng)度不用判斷 top = -1 的情況疯攒,因?yàn)?-1+1 = 0 其最終結(jié)果是一樣的

其實(shí)通過(guò)上述實(shí)現(xiàn)我們可以發(fā)現(xiàn)嗦随,棧的處理核心邏輯在于 top 的處理。

鏈?zhǔn)綏?/h2>

分析了順序棧之后我們?cè)賮?lái)看看鏈?zhǔn)綏>闯撸櫭剂x枚尼,鏈?zhǔn)綏S玫慕Y(jié)構(gòu)就是鏈?zhǔn)酱鎯?chǔ),內(nèi)部必不可少的用到指針砂吞,其在內(nèi)存中不是連續(xù)的署恍,靠的是指針的指向,所以其數(shù)據(jù)結(jié)構(gòu)可以是這樣:

// 棧中每個(gè)位置的數(shù)據(jù)
typedef struct Node {
    Data data;
    Node *next;
} Node;

// 棧的結(jié)構(gòu)
typedef struct {
    Node *top; // 棧頂節(jié)點(diǎn)
    int count; // 棧的數(shù)據(jù)量
} Stack;

這里的鏈?zhǔn)綏5慕Y(jié)構(gòu)就由一個(gè)指向棧頂?shù)闹羔?和 其數(shù)據(jù)長(zhǎng)度構(gòu)成蜻直,棧的指針指向棧頂盯质,由上往下通過(guò) next 指針相連,看起來(lái)應(yīng)該是這樣:


根據(jù)前面鏈表的相關(guān)內(nèi)容概而,我們很容易寫(xiě)出它的相關(guān)方法:

// 創(chuàng)建一個(gè)空棧
Status InitStack(Stack *S) {
    S->top = (Node *)malloc(sizeof(Node));
    if (!S->top) return ERROR;
    S->top = NULL;
    S->count = 0;
    return SUCCESS;
}

// 入棧
Status PushData(Stack *S, Data data) {
    if (!S) return ERROR;
    Node *newTop = (Node *)malloc(sizeof(Node));
    newTop->data = data;
    newTop->next = S->top;
    S->top = newTop;
    S->count++;
    return SUCCESS;
}

// 出棧
Status Pop(Stack *S,Data *data) {
    if (!S) return ERROR;
    Node *temp = S->top;
    S->top = temp->next;
    S->count--;
    *data = temp->data;
    free(temp);
    return SUCCESS;
}

// 獲取棧頂元素
Status GetTop(Stack S,Data *data) {
    if (S.count == 0) return ERROR;
    *data = S.top->data;
    return SUCCESS;
}

// 清空棧
Status ClearStack(Stack *S) {
    Node *temp = S->top;
    while (temp) {
        Node *target = temp;
        temp = temp->next;
        free(target);
    }
    S->top = NULL;
    S->count = 0;
    return SUCCESS;
}

// 從棧頂?shù)綏5状蛴?Status PrintStack(Stack S) {
    if (S.count <= 0) return ERROR;
    printf("棧的數(shù)據(jù)從頂?shù)降资牵?);
    Node *temp = S.top;
    while (temp) {
        printf("%d - ",temp->data);
        temp = temp->next;
    }
    printf("\n");
    return SUCCESS;
}

驗(yàn)證

int main(int argc, const char * argv[]) {
    // insert code here...
    Stack S;
    InitStack(&S);
    if (InitStack(&S) == SUCCESS) {
        for (int i = 1; i < 10; i++) {
            PushData(&S, i);
        }
    }
    PrintStack(S);

    Data data;
    Pop(&S, &data);
    PrintStack(S);
    printf("出棧的元素是: %d \n",data);

    GetTop(S, &data);
    printf("棧頂?shù)脑厥? %d \n",data);
    return 0;
}
--------------------- 打印數(shù)據(jù)
棧的數(shù)據(jù)從頂?shù)降资牵? - 8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 
棧的數(shù)據(jù)從頂?shù)降资牵? - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 
出棧的元素是: 9 
棧頂?shù)脑厥? 8 

總結(jié)

這篇文章主要講述了棧的結(jié)構(gòu)以及棧的 順序存儲(chǔ)實(shí)現(xiàn)鏈?zhǔn)酱鎯?chǔ)實(shí)現(xiàn) 呼巷,希望能夠講述明白。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末赎瑰,一起剝皮案震驚了整個(gè)濱河市王悍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌餐曼,老刑警劉巖压储,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異源譬,居然都是意外死亡集惋,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)踩娘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)芋膘,“玉大人,你說(shuō)我怎么就攤上這事霸饲∥螅” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵厚脉,是天一觀的道長(zhǎng)习寸。 經(jīng)常有香客問(wèn)我,道長(zhǎng)傻工,這世上最難降的妖魔是什么霞溪? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任孵滞,我火速辦了婚禮,結(jié)果婚禮上鸯匹,老公的妹妹穿的比我還像新娘坊饶。我一直安慰自己,他們只是感情好殴蓬,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布匿级。 她就那樣靜靜地躺著,像睡著了一般染厅。 火紅的嫁衣襯著肌膚如雪痘绎。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,146評(píng)論 1 297
  • 那天肖粮,我揣著相機(jī)與錄音孤页,去河邊找鬼。 笑死涩馆,一個(gè)胖子當(dāng)著我的面吹牛行施,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播魂那,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼悲龟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了冰寻?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤皿渗,失蹤者是張志新(化名)和其女友劉穎斩芭,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體乐疆,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡划乖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了挤土。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片琴庵。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖仰美,靈堂內(nèi)的尸體忽然破棺而出迷殿,到底是詐尸還是另有隱情,我是刑警寧澤咖杂,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布庆寺,位于F島的核電站,受9級(jí)特大地震影響诉字,放射性物質(zhì)發(fā)生泄漏懦尝。R本人自食惡果不足惜知纷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望陵霉。 院中可真熱鬧琅轧,春花似錦、人聲如沸踊挠。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)止毕。三九已至模蜡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間扁凛,已是汗流浹背忍疾。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谨朝,地道東北人卤妒。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像字币,于是被迫代替她去往敵國(guó)和親则披。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容