棧的存儲結構


棧:線性結構,后進先出。棧(Stack)是一種特殊的線性表(順序表,鏈表)只在表尾進行刪除和插入操作。

注意:對於棧來說,表尾稱為棧的棧頂(top),表頭稱為棧底(bottom)。

 

棧也是線性結構的一種特例。與隊列不同,他只有一個口,只能從這里讀或者寫數據,這個口稱為棧頂(top)。棧是一種先進后出的數據結構。先進來的元素會放入棧底,而后進來的元素被放在它的上面,最后進來的元素的上面的位置,稱為棧頂。
棧所提供的操作比一般的線性表要少很多,只提供:初始化、銷毀、判斷是否為空、求棧的長度、清空棧、將數據壓入棧、將數據彈出棧、得棧頂元素這幾種操作。其中將數據壓入棧、將數據彈出棧、獲得棧頂元素是最重要的。有人可能覺得,將棧頂元素彈出與獲得棧頂元素是不是有點重復,其實它們主要的目的在於,很多時候你只想知道當前棧頂的元素是誰,而並不想將它彈出。這樣做可以簡單一點。
了解了棧的基本結構和操作以后,自然而然的想到用數組來實現棧:因為前面的元素並不發生變化,只能在最后面入棧或者出棧。

因為棧的本質是一個線性表,線性表有兩種存儲形式,那么棧也有分為棧的順序存儲結構和棧的鏈式存儲結構。

最開始棧中不含有任何數據,叫做空棧,此時棧頂就是棧底。然后數據從棧頂進入,棧頂棧底分離,整個棧的當前容量變大。數據出棧時從棧頂彈出,棧頂下移,整個棧的當前容量變小。

棧頂——地址較高;

棧底——地址較低。 

定義一個順序存儲的棧,包含三個元素:base、top、stackSize。

[cpp]  view plain  copy
 print ? 在CODE上查看代碼片 派生到我的代碼片
  1. typedef struct{  
  2. ElemType *base;//棧底  
  3. ElemType *top;//棧頂  
  4. int stackSize;//棧的當前可使用的最大容量  
  5. }sqStack;  

或者:

[cpp]  view plain  copy
 print ? 在CODE上查看代碼片 派生到我的代碼片
  1. typedef int ElemType;  
  2.  typedef struct{  
  3. ElemType data[MAXSIZE];  
  4. int top;    // 用於標注棧頂的位置  
  5. int stackSize;  
  6. }  
其中base是指棧底的指針變量,top是指棧頂的指針變量,stackSize指棧的當前可使用的最大容量。

創建一個棧:

[cpp]  view plain  copy
 print ? 在CODE上查看代碼片 派生到我的代碼片
  1. #define STACK_INIT_SIZE 100  
  2.    
  3. initStack(sqStack *s){  
  4. s->base = (ElemType *)malloc( STACK_INIT_SIZE * sizeof(ElemType) );  
  5. if( !s->base )  
  6. exit(0);  
  7.    
  8. s->top = s->base;   // 最開始,棧頂就是棧底  
  9. s->stackSize = STACK_INIT_SIZE;  
  10. }  

入棧操作:

入棧操作又叫壓棧操作,就是向棧中存放數據。

入棧操作要在棧頂進行,每次向棧中壓入一個數據,top指針就要+1,直到棧滿為止。 

出棧操作:

出棧操作就是在棧頂取出數據,棧頂指針隨之下移的操作。

每當從棧內彈出一個數據,棧的當前容量就-1。 

入棧時,先將值壓入棧中,再改變指針top,即將top指針加1;

出棧時,先將top指針減去1,然后再將top指針指向的值從棧中取出;

注意:top指針在開始時指向的位置其實就是將要存放數據的位置,因此它指向的區域是空的,想要將數據從棧中取出,需要首先將top指針指向該位置。

[cpp]  view plain  copy
 print ? 在CODE上查看代碼片 派生到我的代碼片
  1. Pop(sqStack *s, ElemType *e){  
  2. if( s->top == s->base )  // 棧為空  
  3. return;  
  4. *e = *--(s->top);  
  5. }  

棧的其它操作:清空、銷毀、計算棧的當前容量等。

1、清空:清空一個棧,就是將棧中的元素全部作廢,但棧本身物理空間並不發生改變(不是銷毀)。

因此我們只要將s->top的內容賦值為s->base即可,這樣s->base等於s->top,也就表明這個棧是空的了。

這個原理跟高級格式化只是但單純地清空文件列表而沒有覆蓋硬盤的原理是一樣的。

[cpp]  view plain  copy
 print ? 在CODE上查看代碼片 派生到我的代碼片
  1. ClearStack(sqStack*s){  
  2. s->top= s->base;  
  3. }  
2、 銷毀一個棧

銷毀一個棧與清空一個棧不同,銷毀一個棧是要釋放掉該棧所占據的物理內存空間,因此不要把銷毀一個棧與清空一個棧這兩種操作混淆。

[cpp]  view plain  copy
 print ? 在CODE上查看代碼片 派生到我的代碼片
  1. DestroyStack(sqStack *s){  
  2. int i, len;   
  3. len = s->stackSize;  
  4.    
  5. for( i=0; i < len; i++ )  
  6. {  
  7. free( s->base );  
  8. s->base++;  
  9. }  
  10.    
  11. s->base = s->top = NULL;  
  12. s->stackSize = 0;  
  13. }  
3、計算棧的當前容量 

計算棧的當前容量也就是計算棧中元素的個數,因此只要返回s.top-s.base即可。

注意,棧的最大容量是指該棧占據內存空間的大小,其值是s.stackSize,它與棧的當前容量不是一個概念哦。 

[cpp]  view plain  copy
 print ? 在CODE上查看代碼片 派生到我的代碼片
  1. int StackLen(sqStack s){  
  2. return(s.top – s.base);  
  3. //兩個地址相減,返回的是存放在該地址的數據的個數  
  4. }  
(指針的數學計算:++、--、相減,但是指針不能相加!) 

 

棧的鏈式存儲結構(棧鏈)

棧因為只是棧頂來做插入和刪除操作,所以比較好的方法就是將棧頂放在單鏈表的頭部,棧頂指針和單鏈表的頭指針合二為一。


[cpp]  view plain  copy
 print ? 在CODE上查看代碼片 派生到我的代碼片
  1. //棧的鏈式存儲結構(棧鏈)  
  2. teypedef struct StackNode  
  3. {  
  4.     ElemType data;      // 存放棧的數據  
  5.     struct StackNode *next;  
  6. } StackNode, *LinkStackPtr;  
  7.   
  8. teypedef struct LinkStack  
  9. {  
  10.     LinkStackPrt top;   // top指針  
  11.     int count;    // 棧元素計數器  
  12. }  
  13. //對於棧鏈的Push操作,假設元素值為e的新結點是s,top為棧頂指針  
  14. Status Push(LinkStack *s, ElemType e){  
  15.     LinkStackPtr p = (LinkStackPtr) malloc (sizeof(StackNode));  
  16.     p->data = e;  
  17.     p->next = s->top;  
  18.     s->top = p;  
  19.     s->count++;  
  20.     return OK;  
  21. }  
  22. //鏈棧的出棧Pop操作,假設變量p用來存儲要刪除的棧頂結點,將棧頂指針下移一位,最后釋放p即可。  
  23. Status Pop(LinkStack *s, ElemType *e){  
  24.     LinkStackPtr p;  
  25.     if( StackEmpty(*s) )  // 判斷是否為空棧  
  26.         return ERROR;  
  27.    
  28.     *e = s->top->data;  
  29.     p = s->top;  
  30.     s->top = s->top->next;  
  31.     free(p);  
  32.     s->count--;   
  33.     return OK;  
  34. }  


免責聲明!

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



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