作者:Vamei 出處:http://www.cnblogs.com/vamei 歡迎轉載,也請保留這段聲明。謝謝!
棧(stack)是簡單的數據結構,但在計算機中使用廣泛。它是有序的元素集合。棧最顯著的特征是LIFO (Last In, First Out, 后進先出)。當我們往箱子里存放一疊書時,先存放的書在箱子下面,我們必須將后存放的書取出來,才能看到和拿出早先存放的書。
棧中的每個元素稱為一個frame。而最上層元素稱為top frame。棧只支持三個操作, pop, top, push。
pop取出棧中最上層元素(8),棧的最上層元素變為早先進入的元素(9)。
top查看棧的最上層元素(8)。
push將一個新的元素(5)放在棧的最上層。
棧不支持其他操作。如果想取出元素12, 必須進行3次pop操作。
棧以及pop, push, top操作
棧最經典的計算機應用是函數調用。每個進程都會有一個棧,每個frame中記錄了調用函數的參數,自動變量和返回地址。當該函數調用一個新的函數時,棧中會 push一個frame。當函數執行完畢返回時,該frame會pop,從而進入調用該函數的原函數,繼續執行。詳細請參閱Linux從程序到進程
實際使用的棧並不一定符合數據結構的棧。比如說,有的語言允許被調用函數查看非top frame的記錄。這樣的棧更類似於下面的經典游戲
棧的C實現 (基於表)
由於棧是限定了操作的有序的元素集合,所以我們既可以在數組的基礎上來實現棧,也可以在表的基礎上來實現棧。如果使用數組來實現棧,我們需要預留充足的空間供棧使用,並需要一個下標來記錄最上層元素的位置。
我們這里使用單向鏈表來實現棧。我們可以利用介紹表(list)的文章中已經定義的操作來實現三個操作,但這里相對獨立的重寫了代碼。
/* By Vamei */ /* use single-linked list to implement stack */ #include <stdio.h> #include <stdlib.h> typedef struct node *position; typedef int ElementTP; // point to the head node of the list typedef struct node *STACK; struct node { ElementTP element; position next; }; STACK init_stack(void); void delete_stack(STACK); ElementTP top(STACK); void push(STACK, ElementTP); ElementTP pop(STACK); int is_null(STACK); void main(void) { ElementTP a; int i; STACK sk; sk = init_stack(); push(sk, 1); push(sk, 2); push(sk, 8); printf("Stack is null? %d\n", is_null(sk)); for (i=0; i<3; i++) { a = pop(sk); printf("pop: %d\n", a); } printf("Stack is null? %d\n", is_null(sk)); delete_stack(sk); } /* * initiate the stack * malloc the head node. * Head node doesn't store valid data * head->next is the top node */ STACK init_stack(void) { position np; STACK sk; np = (position) malloc(sizeof(struct node)); np->next = NULL; // sk->next is the top node sk = np; return sk; } /* pop out all elements * and then delete head node */ void delete_stack(STACK sk) { while(!is_null(sk)) { pop(sk); } free(sk); } /* * View the top frame */ ElementTP top(STACK sk) { return (sk->next->element); } /* * push a value into the stack */ void push(STACK sk, ElementTP value) { position np, oldTop; oldTop = sk->next; np = (position) malloc(sizeof(struct node)); np->element = value; np->next = sk->next; sk->next = np; } /* * pop out the top value */ ElementTP pop(STACK sk) { ElementTP element; position top, newTop; if (is_null(sk)) { printf("pop() on an empty stack"); exit(1); } else { top = sk->next; element = top->element; newTop = top->next; sk->next = newTop; free(top); return element; } } /* check whether a stack is empty*/ int is_null(STACK sk) { return (sk->next == NULL); }
輸出結果:
Stack is null? 0
pop: 8
pop: 2
pop: 1
Stack is null? 1
總結
棧, LIFO
pop, push, top
歡迎繼續閱讀“紙上談兵: 算法與數據結構”系列。
Update:
我之前是用雙向循環鏈表實現的棧,后來發現這樣沒有必要。它不能給棧帶來額外的好處,還會增加所需的內存空間。