數據結構之棧定義及基本操作實現


 

  終於有可以有時間寫點數據結構的學習總結了,前段時間一直在緊張的忙一些項目,都沒有空出時間來學習數據結構,現在終於可以稍微喘口氣了,還是數據結構有意思,這兩天看了點棧的東西,寫下來總結一下,有錯誤的地方希望看到的朋友指出來,感激不盡。

  根據學習,棧就是一種線性數據結構,棧的運算只能在表的一段進行,所以這種數據結構具有“后進先出”的特點。

  接下來是棧的c語言實現。其中棧由一個top節點和bottom節點組成,這兩個節點分別指向棧的頂部和底部。其中棧的組成結點是由結構體實現,結構體由數據庫和指向下一個結點的指針域構成,下面是結點的c語言實現:

1 /*
2 定義實現棧的結點 
3 */
4 typedef struct Node{
5     int data;
6     struct Node * pNext;
7 }NODE,* PNODE;

  有了實現棧的結點,那么接下來就是該如何實現棧(具體的解釋看代碼):

1 /*
2 定義棧的結構,此處采用鏈表實現靜態棧,所以僅僅需要給出棧的頭部指針和底部指針即可 
3 */
4 typedef struct Strack{
5     PNODE pTop;
6     PNODE pBottom;
7 }STRACK,* PSTRACK;

  棧的基本操作:棧的初始化,壓棧、棧的遍歷、出棧等操作  

 1 /*
 2 對棧初始化的函數
 3 對棧初始化僅僅是令棧中的top和bottom指針指向一個確定的地址,並且此地址指向的是棧的頭結點(頭結點的引入可以
 4 大大方便對棧的操作)。 
 5 */
 6 void init_strack(PSTRACK pS){
 7     pS->pTop=(PNODE)malloc(sizeof(NODE));   //定義一個新結點,這個結點就是棧的頭結點,並且讓pTop指向這個結點
 8     if(pS->pTop==NULL){
 9         printf("內存分配失敗");
10         exit(-1);
11     } 
12     else{
13         pS->pBottom=pS->pTop;    //令bottom和top都指向頭結點,則初始化棧完成,棧中沒有任何有效結點
14         pS->pTop->pNext=NULL; 
15     }
16      
17 }
18 
19 /*
20 壓棧函數
21 因為棧具有“先進后出、后進先出”的特性,所以,在將元素壓入棧時,也只能將棧壓入棧的頂部
22 由此,壓棧函數就是令棧的top指針指向新結點,新結點的指針域指向未壓入棧時的最頂部的元素。 
23 */
24 int push(PSTRACK pS,int val){
25     PNODE pNew=(PNODE)malloc(sizeof(NODE));  //定義一個新結點
26     if(pNew->pNext==NULL){
27         printf("內存分配失敗");
28         exit(-1);
29     }
30     pNew->data= val;
31     pNew->pNext=pS->pTop;  //指針賦值的順序不可以亂,為保證top所指向的地址不丟失,所以首先讓新結點的指針域指向pS->pTop所指向的結點
32     pS->pTop=pNew;  //令top指針指向新的結點
33     return 0; //0表示當前push成功 
34 }
35 
36 /*
37 棧的遍歷函數
38 因為只是遍歷輸出,所以不能破壞棧原有的結構,所以我們只有定義一個新的結點p,讓其指向棧頂元素,
39 然后遍歷下移一個輸出其指向的元素的值 ,循環條件就是p=ps->pBottom 
40 */
41 void traverse(PSTRACK ps){
42     PNODE p=ps->pTop;  //讓新定義的結構體指針指向棧頂元素
43     while(p!=ps->pBottom){
44         printf("%d ", p->data);
45         p=p->pNext;  //讓當前指針指向當前節點的下一個結點 
46     } 
47     printf("\n");
48     return;
49 }
50 
51 
52 /*
53 判斷當前棧是否為空的函數
54 若為空,返回true
55 否則,返回false 
56 */
57 bool isEmpty(PSTRACK ps){
58     if(ps->pTop==ps->pBottom){
59         return true;
60     }
61     else{
62         return false;
63     }
64 }
65 
66 /*
67 彈棧函數:彈棧簡單的說就是將第一個數值彈出,然后將ps->pTop指向原第一個結點的下一個結點(即彈棧后的第一個結點),
68 然后在將被彈出的元素在內存中釋放掉。 
69 */
70 bool pop(PSTRACK ps,int *pVal){
71     if(isEmpty(ps)){  //判斷當前棧是否為空,若為空,則返回false 
72         return false;
73     }
74     else{   
75         PNODE p=ps->pTop;  //定義一個結點,這個結點在每次彈棧時都是指向棧頂,這樣可以保證不會造成被彈出元素的丟失 
76         ps->pTop=p->pNext;  //讓top結點指向棧頂元素 
77         *pVal=p->data;
78         free(p);  //將被彈出元素釋放 
79         p=NULL;
80         return true;
81     }     
82 }

  上述就實現了對棧的基本操作,當然具體的應用還要看具體的算法要求。

 

上述是在大學時學習的,下面的是工作兩年后再次學習時的理解,可能會有不同的見解,都寫出來吧。

1、棧的定義:一種可以實現“先進后出”的數據存儲結構,數據的插入和刪除只能在數據的一端進行。
內存分為靜態內存和動態內存。
靜態內存在棧中分配;動態內存在堆中分配。
棧:由操作系統自動分配釋放,存放函數的參數值, 局部變量的值等。
堆:一般由程序猿分配釋放,若程序猿不釋放,程序結束時由OS回收(類似於c語言中的malloc函數分配的空間)。
 
2、棧的分類:
(1)靜態棧:以數組作為數據的存儲。
(2)動態棧:以鏈表作為數據的存儲方式。
 
3、棧的相關操作(該處采用鏈表的動態棧):
一點說明:
     因為用鏈表實現棧,其實其本質就是一個鏈表,只不過對該鏈表的插入(push)和刪除(pop)操作都在該鏈表的一端進行(該段被稱為棧頂,且人為限制就只在該棧頂進行操作),所以該鏈表就會具有了“先進后出”的特性,則被稱為棧結構。
     所以,嚴格來說,棧僅僅需要一個棧頂,該棧頂指向該鏈表的被稱為棧頂端的節點(所以,該棧頂也是一個該Node類型的指針)。
(1)棧中每個節點的結構:

 

 
(2)棧的結構:
因為通過棧頂可以找到該棧的所有元素,所以,該棧對應的鏈表應該是一個自上而下指向的鏈表。
該棧僅需要一個stop指針,指向棧頂元素。
 

 

(3)棧的初始化操作:
 

 

(4)棧的push操作:
 

 

(5)棧的pop操作:
 

 

(6)棧是否為空及棧的遍歷操作:
 

 

其實在棧中可以增加一個PNODE類型的指針sbuttom,讓該指針用於指向棧低節點,在判斷非空時,只要判斷sc->stop == sc->sbuttom時,就表示top和buttom重合了,指向了最底部的節點。其實,該buttom節點可以通過最后一個節點的next指針域是否為NULL來判斷(next指針域為NULL時,就表示該節點沒有下一個節點了,是棧低節點)。 
 
代碼:
  1 #include <stdio.h>
  2 #include <sys/malloc.h>
  3 #include <stdlib.h>
  4 
  5 /*
  6 棧結構及其操作:
  7 當前采用鏈表進行棧中數據的存儲。
  8 */
  9 
 10 
 11 /*
 12 定義棧中每一個節點的結構
 13 */
 14 typedef struct Node{
 15     int data;  //數據域
 16     struct Node * pnext;  //指針域,指向棧中下一個節點
 17 }NODE, * PNODE;  //定義兩個別名,方便操作
 18 
 19 /*
 20 定義棧的結構:
 21 因為用鏈表實現棧,其實其本質也是一個鏈表,只不過該鏈表的插入(push)和刪除(pop)操作只能在鏈表的一端(該端被稱作棧頂)進行操作,所以該鏈表具有“先進后出”的特性,被稱作棧(個人理解)。
 22 所以,嚴格來說,棧僅僅需要一個指向棧頂(鏈表的一端)struct Node *類型的指針就可以知道該棧中的所有數據。
 23 */
 24 typedef struct Stack{
 25     struct Node * stop;  //棧的棧頂(指向棧中最頂部的那個元素)
 26 } STACK;
 27 
 28 //棧的初始化操作
 29 struct Stack init_stack();
 30 
 31 //push操作
 32 void stack_push(STACK *sc, int data);
 33 
 34 //pop操作
 35 int pop(STACK *sc);
 36 
 37 //遍歷操作
 38 void trvel_stack(STACK *sc);
 39 
 40 //判斷是否為空操作
 41 int is_empty(STACK *sc);
 42 
 43 int main(int argc, char const *argv[])
 44 {
 45     STACK sc;
 46     sc = init_stack();
 47 
 48     //push幾個數據
 49     stack_push(&sc, 1);
 50     stack_push(&sc, 3);
 51     stack_push(&sc, 7);
 52     stack_push(&sc, 2);
 53     stack_push(&sc, 10);
 54 
 55     //遍歷
 56     trvel_stack(&sc);
 57 
 58     //pop一個數據出來
 59     pop(&sc);
 60 
 61     trvel_stack(&sc);
 62 
 63     return 0;
 64 }
 65 
 66 /*
 67 棧的初始化操作
 68 */
 69 struct Stack init_stack(){
 70     //先定義一個棧
 71     STACK sc;
 72 
 73     //初始化棧中的第一個節點(棧低節點),該節點並沒有什么實際意義,不存放數據
 74     PNODE pbottom = (PNODE)malloc(sizeof(NODE));
 75     if (pbottom == NULL) {
 76         printf("內存分配失敗\n");
 77         exit(1);
 78     }
 79     pbottom->pnext = NULL;
 80 
 81     //將棧頂指向該元素
 82     sc.stop = pbottom;
 83 
 84     return sc;
 85 }
 86 
 87 /*
 88 棧的push操作
 89 */
 90 void stack_push(STACK *sc, int data){
 91     printf("調用了!\n");
 92 
 93     //新創建一個節點
 94     PNODE pnew = (PNODE)malloc(sizeof(NODE));
 95     printf("%p\n", pnew);
 96     if (pnew == NULL) {
 97         printf("內存分配失敗\n");
 98         exit(1);
 99     }
100     pnew->data = data;
101 
102     //將新節點指向原top節點,將棧的top指向該新節點
103     pnew->pnext = sc->stop;
104     sc->stop = pnew;
105 }
106 
107 /*
108 棧的pop操作
109 */
110 int pop(STACK *sc){
111     int res;
112     //判斷棧是否為空
113     if (is_empty(sc) == 1){
114         printf("棧為空,不可pop\n");
115         exit(1);
116     } else {
117         PNODE ptmp = sc->stop;  //先將需要被pop出的節點存儲起來
118         sc->stop = sc->stop->pnext;  //將棧的top指向下一個節點
119         res = ptmp->data;
120         free(ptmp);  //將地址釋放
121         return res;
122     }
123 }
124 
125 /*
126 判斷棧是否為空的操作
127 */
128 int is_empty(STACK *sc){
129     PNODE p = sc->stop;
130     if (p == NULL || p->pnext == NULL) {
131         return 1;  //true表示為空
132     } else {
133         return 0;  //false表示非空
134     }
135 }
136 
137 /*
138 遍歷棧
139 */
140 void trvel_stack(STACK *sc){
141     if (is_empty(sc) == 1) {
142         printf("棧為空喲,無法遍歷呢~\n");
143         exit(1);
144     } else {
145         printf("遍歷調用了!\n");
146         PNODE ptmp = sc->stop;
147         while (ptmp->pnext != NULL) {  //直到最后一個為NULL的節點,該節點就是最后一個節點
148             printf("%d\n", ptmp->data);
149             ptmp = ptmp->pnext;
150         }
151     }
152     
153 }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM