順序棧的實現和兩棧共享空間


順序棧的實現和兩棧共享空間

 以后慢慢啟用個人博客:http://www.yuanrengu.com/

一.順序棧的實現     

       棧(stack)是限定僅在表尾進行插入或刪除操作的線性表。我們把允許插入和刪除的一端稱為棧頂(top),另一端稱為棧底(bottom),不含任何數據元素的棧稱為空棧。棧又稱為后進先出(Last In First Out)的線性表,簡稱LIFO結構。

理解棧的定義需要注意:

  1. 首先他是一個線性表,也就是說,棧元素具有線性關系,即前驅后繼關系。只不過他是一種特殊的線性表而已。定義中說是在線性表的表尾進行插入和刪除操作,這里表尾是指棧頂,而不是棧底。
  2. 他的特殊之處就在於限制了這個線性表的插入和刪除位置,他始終只在棧頂進行。這也就使得:棧底是固定的,最先進棧的只能在棧底。

      棧的插入操作,叫作進棧,也稱壓棧、入棧。棧的刪除操作,叫出棧,也稱彈棧。

     順序棧,即棧的順序存儲結構是利用一組地址連續的存儲單元依次存放自棧底到棧頂的數據元素,同時附設指針top指示棧頂元素在順序棧中的位置。

順序棧的定義:

typedef struct{
    ElemType *bottom;
    ElemType *top;
    int StackSize;
}SqStack;

其中,StackSize指示棧的當前可使用的最大容量。棧的初始化操作為:按設定的初始狀態分配量進行第一次存儲分配,bottom可稱為棧底指針,在順序棧中,他始終指向棧底的位置,如bottom的值為NULL,則表明棧結構不存在。稱top為棧頂指針,其初值指向棧底,即top=bottom可作為棧空的標記,每當插入新的棧頂元素時,指針top增1;刪除棧頂元素時,指針top減1,因此,非空棧中的棧頂指針始終在棧頂元素的下一個位置上。如下圖所示。

base = NULL;  //棧結構不存在
top = base;   //棧空

順序棧的實現:

頭文件stack.h

 1 //stack.h
 2 
 3 #define TRUE        1  
 4 #define FALSE       0  
 5 #define OK          1  
 6 #define ERROR       0  
 7 #define OVERFLOW    -1  
 8 #define UNDERFLOW   -2  
 9 
10  
11 
12 //定義函數返回值類型  
13 typedef int  Status;  
14 //定義順序棧的數據元素的類型  
15 typedef int  ElemType;
16 
17    
18 //定義順序棧的存儲結構  
19 
20 #define STACK_INIT_SIZE 100 //初始分配空間大小
21 
22 #define INCREMENTSIZE   10 //存儲空間分配增量  
23 struct SeqStack{  
24     ElemType    *bottom;    //棧底指針  
25     ElemType    *top;       //棧頂指針  
26     int      size;       //棧存儲空間大小  
27 };
28 
29 //聲明順序棧的基本操作  
30 Status  InitStack(SeqStack &s);  //構造一個空棧
31 Status  DestroyStack(SeqStack &s);  //銷毀一個棧
32 Status  ClearStack(SeqStack &s);  //把棧置空
33 Status  StackEmpty(SeqStack s);  //判斷是否為空棧
34 Status  StackLength(SeqStack s);  //返回棧的長度(即元素個數)
35 Status  Push(SeqStack &s,ElemType e);  //元素入棧
36 Status  Pop(SeqStack &s,ElemType &e);  //元素出棧
37 Status  GetTop(SeqStack s,ElemType &e);  //返回棧頂元素
38 Status  StackTraverse(SeqStack s);   //遍歷棧
stack.h

實現函數:stack.cpp

  1 #include "stack.h"
  2 #include <iostream>
  3 using namespace std;
  4 
  5 Status  InitStack(SeqStack &s)  
  6 //操作結果:構造一個空棧S  
  7 {   
  8     s.bottom=(ElemType*)malloc(STACK_INIT_SIZE*sizeof(ElemType));  
  9     if(s.bottom == NULL){  
 10         cout<<"嚴重錯誤:順序棧初始存儲空間分配失敗,程序退出";  
 11         exit(ERROR);  
 12     }   
 13     s.top=s.bottom;
 14     s.size=STACK_INIT_SIZE;   
 15     return OK;  
 16 }  
 17 
 18 Status  DestroyStack(SeqStack &s)  
 19 //初始條件:棧s已存在  
 20 //操作結果:棧s已被銷毀  
 21 {  
 22     free(s.bottom);   
 23     s.bottom=s.top=NULL;  //s.bottom的值為NULL,表示順序棧不存在   
 24     s.size=0;  
 25     return OK;  
 26 }  
 27 
 28 Status  ClearStack(SeqStack &s)  
 29 //初始條件:棧s已存在  
 30 //操作結果:將s清為空棧  
 31 {   
 32     s.top=s.bottom;  //s.top == s.bottom作為順序棧空的標記  
 33     return OK;  
 34 }  
 35 
 36 Status  StackEmpty(SeqStack s)  
 37 //初始條件:棧s已存在  
 38 //操作結果:若棧s為空棧,則返回TRUE,否則FALSE  
 39 {  
 40     if(s.top == s.bottom)  
 41         return TRUE;  
 42     else 
 43         return FALSE;  
 44 }  
 45 
 46 Status StackLength(SeqStack s)  
 47 //初始條件:棧s已存在  
 48 //操作結果:返回s的元素個數,即棧的長度  
 49 {  
 50     return s.top-s.bottom;  
 51 }  
 52 
 53 Status  Push(SeqStack &s,ElemType e)  
 54 //初始條件:棧s已存在  
 55 //操作結果:插入元素e成為新的棧頂元素  
 56 {       
 57    if(s.top-s.bottom >= s.size ){   
 58         s.bottom=(ElemType*)realloc(s.bottom,(s.size+INCREMENTSIZE)*sizeof(ElemType));  
 59         if(s.bottom == NULL){  
 60             cout<<"嚴重錯誤:順序棧增量存儲空間分配失敗,程序退出!";  
 61             exit(OVERFLOW);  
 62         }    
 63         s.top=s.bottom+s.size;   
 64         s.size+=INCREMENTSIZE;  
 65     }   
 66 
 67    // *s.top=e;
 68     //s.top++;  
 69    *s.top++ = e;
 70     return OK;  
 71 }  
 72 
 73 Status  Pop(SeqStack &s,ElemType &e)  
 74 //初始條件:棧s已存在且非空  
 75 //操作結果:刪除s的棧頂元素,並且用e返回其值  
 76 {  
 77     if(StackEmpty(s) == TRUE){  
 78         cout<<"順序棧為空,出棧失敗!"<<endl;  
 79         exit(UNDERFLOW);  
 80     }  
 81    // s.top--;
 82    // e=*s.top;  
 83     e = *--s.top;
 84     return OK;  
 85 }   
 86  
 87 Status  GetTop(SeqStack s,ElemType &e)  
 88 //初始條件:棧s已存在且非空  
 89 //操作結果:用e返回s的棧頂元素  
 90 {  
 91     if( StackEmpty(s) == TRUE ){  
 92         cout<<"訪問棧頂元素發生錯誤:棧為空"<<endl;  
 93         exit(UNDERFLOW);  
 94     }   
 95     return *(s.top-1);  
 96 }  
 97 
 98 Status  StackTraverse(SeqStack s)  
 99 //初始條件:棧s已存在且非空  
100 //操作結果:從棧底開始依次輸出
101 {  
102     if(s.bottom == NULL){  
103         cout<<"嚴重錯誤:棧不存在,程序退出!";  
104         exit(ERROR);  
105     }   
106     for(int i=0;i < StackLength(s);i++)   
107     //    cout<<s.bottom[i]<<endl;   
108         cout<<s.bottom[i]<<endl;  
109     return OK;  
110 }
stack.cpp

測試函數:

 1 //test.cpp
 2 
 3 #include "stack.h"   
 4 #include <iostream>
 5 using namespace std;
 6 
 7 //獲取隨機整數  
 8 int RangedRand( int range_min, int range_max)   
 9 {   
10    // Generate random numbers in the half-closed interval   
11    // [range_min, range_max). In other words,   
12    // range_min <= random number < range_max   
13    int u =(int)( (double)rand() / (RAND_MAX + 1) * (range_max - range_min)   
14             + range_min );    
15    return u;   
16 }   
17   
18   
19 int main()   
20 {   
21     struct SeqStack s;   
22     InitStack(s);     
23     ElemType data[10];   
24     for(int i=0;i<10;i++){   
25         data[i]=RangedRand(-500,500);   
26         Push(s,data[i]);   
27     }   
28   
29     StackTraverse(s);   
30     cout<<"順序棧的長度是:"<<StackLength(s)<<endl;   
31   
32     ElemType e;   
33     Pop(s,e);   
34     cout<<"棧頂元素"<<e<<"出棧"<<endl;   
35     cout<<"此時的順序棧:"<<endl;   
36     StackTraverse(s);   
37     cout<<"順序棧的長度是:"<<StackLength(s)<<endl;   
38   
39     DestroyStack(s);   
40     StackTraverse(s);   
41     cout<<"順序棧的長度是:"<<StackLength(s)<<endl;   
42 
43 
44     return 0;   
45 }
test.cpp

 

二.兩棧共享空間

      如果我們有兩個相同類型的棧,我們為他們各自開辟了數組空間,極有可能第一個棧已經滿了,再進棧就溢出了,而另一個棧還有很多存儲空間空閑。這時,我們完全可以用一個數組兩存儲兩個棧。

      我們的做法如下圖,數組有兩個端點,兩個棧有兩個棧底,讓一個棧的棧底為數組的始端,即下標為0處,另一個棧為數組的末端,即下標為數組長度n-1處。這樣,兩個棧如果增加元素,就是兩端點向中間延伸。

     其實關鍵思路是:他們是在數組的兩端,向中間靠攏。top1和top2是棧1和棧2的棧頂指針,可以想象,只要他們兩不見面,兩個棧就可以一直使用。

     從這里也就可以分析出來,棧1為空時,就是top1等於-1時;而當top2等於n時,即是棧2為空時,那么什么時候棧滿呢?

     想想極端的情況,若棧2是空棧,棧1的top1等於n-1時,就是棧1滿了。反之,當棧1為空棧時,top2等於0時,為棧2滿。但更多的情況,其實就是剛才說的,兩個棧見面之時,也就是兩個指針之間相差1時,即top1+1==top2為棧滿

     兩棧共享空間的結構的代碼如下:

typedef struct
{
    ElemType data[MAXSIZE];
    int top1;  //棧1棧頂指針
    int top2;  //棧2棧頂指針
}SqDoubleStack;

      對於兩棧共享空間的push方法,我們除了要插入元素值參數外,還需要有一個判斷是棧1還是棧2的棧號參數stackNumber。插入元素的代碼如下:

 1 Status Push(SqDoubleStack *s , ElemType e , int stackNumber)
 2 {
 3     if(s->top1+1 == s->top2)       //棧已滿,不能再push新元素了
 4         return ERROR;
 5     if(stackNumber == 1)           //棧1有元素進棧
 6         s->data[++s->top1] = e;    //若棧1則先top+1后給數組元素賦值
 7     else if(stackNumber == 2)      //棧2有元素進棧
 8         s->data[--s->top2] = e;    //若棧2則先top2-1后給數組元素賦值
 9     return OK;
10 
11 }

      因為在開始已經判斷了是否有棧滿的情況,所以后面的top1+1或top2-1是不擔心溢出問題的。

      對於兩棧共享空間的pop方法,參數就只是判斷棧1棧2的參數stackNumber,代碼如下:

 1 //若棧不空,則刪除s的棧頂元素,用e返回其值,並返回OK;否則返回ERROR
 2 Status Pop(SqDoubleStack *s , ElemType *e , int stackNumber)
 3 {
 4     if(stackNumber == 1)
 5     {
 6         if(s->top1 == 1)
 7             return ERROR;            //說明棧1已經是空棧,溢出
 8         *e = s->data[s->top1--];     //將棧1的棧頂元素出棧 
 9     }
10     else if(stackNumber == 2)
11     {
12         if(s->top2 == MAXSIZE)
13             return ERROR;            //說明棧2已經是空棧,溢出
14         *e = s->data[s->top2++];     //將棧2的棧頂元素出棧
15     }
16     return OK;
17 }

      事實上,使用這樣的數據結構,通常都是當兩個棧的空間需求有相反關系時,也就是一個棧增長時另一個棧在縮短的情況。

      注意:這只是針對兩個具有相同數據類型的棧。

 

 


免責聲明!

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



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