1. 程式人生 > >資料結構與演算法分析 - 2 - 棧ADT

資料結構與演算法分析 - 2 - 棧ADT

1.描述:實質是一種受到限制的表,即插入刪除只能在表的末端,能夠實現LIFO(後進先出)

2.棧的實現

  連結串列實現(鏈棧)

  陣列實現(順序棧)

 

3.鏈棧

建立一個空棧

 1 struct Node 
 2 {
 3     int value;
 4     Node *next;
 5 };
 6 
 7 //建立了一個頭節點為S的鏈棧,S將一直表示棧頂元素
 8 Node *CreatStack()
 9 {
10     Node *S = new Node;
11     S->next = NULL;
12     return S;
13 }

 

測試棧是否為空

1 int IsEmpty(Node *S)
2 {
3     return S->next == NULL;
4 }

 

從棧頂彈出元素

 1 void Pop(Node *S)
 2 {
 3     Node *FirstCell;
 4     if (IsEmpty(S))                  //空棧,將返回異常
 5         cout << "Empty Stack" << endl;
 6     else
 7     {
 8         FirstCell = S->next;            //取出棧頂
9 S->next = S->next->next;         //使S指向新的棧頂 10 delete FirstCell;             //刪除原棧頂,完成出棧 11 } 12 }

 

返回棧頂元素(不彈出,不改變棧頂指標),遇到空棧將返回異常

1 int Top(Node *S)
2 {
3     if (!IsEmpty(S))
4         return S->next->value;
5 }

 

清空棧(同時銷燬實體記憶體)

1 void MakeEmpty(Node *S)
2 { 3 while (!IsEmpty(S)) 4 Pop(S); 5 }

 

壓棧

 1 void Push(int x, Node *S)
 2 {
 3     Node *TempCell = new Node;
 4     if (TempCell == NULL)
 5         cout << "Out of space" << endl;
 6     else
 7     {
 8         TempCell->value = x;          //把x賦值給value
 9         TempCell->next = S->next;        //將新節點設為棧頂
10         S->next = TempCell;           //使S指向新的棧頂
11     }
12 }

 

遍歷棧

1 void Print(Node *S)
2 {
3     Node *p = S->next;        //將p初始化為棧頂
4     while (p != NULL)
5     {
6         cout << p->value << endl;
7         p = p->next;
8     }
9 }

 

注意,記憶體分配操作的時間開銷較大(C的malloc和free,C++的new和delete),可用通過建立第二個棧來避免,第一個棧中的元素彈出時將不會被刪除,而是暫時存放在第二個棧中,然後當第一個棧需要新的元素時,將首先在第二個棧中查詢,由於在鏈棧中,所有的操作均花費常數時間,所以檢索第二個棧的開銷相對於記憶體分配是值得的。

 

宣告一個Stack連結串列

1 struct Stack 
2 {
3     Node *top;        //top指向棧頂
4     Node *bottom;      //bottom指向棧底
5 };

這樣在任意Node處都可以通過p->top或者p->bottom的方式獲得當前棧的棧頂和棧底

 

判斷棧是否為空也可以這樣進行 

1 int IsEmpty(Node *p)
2 {
3     if (p->top == p->bottom)     //棧頂和棧底相同
4         return 1;
5     else
6         return 0;
7 }

 

4.順序棧

陣列實現的順序棧避免了使用指標,順序棧使用一個一維陣列來存放棧的元素

每一個棧有一個TopOfStack,對於空棧來說TopOfStack = -1

壓棧時,將TopOfStack加1,Stack[TopOfStack] = x;出棧時,減1

1 typedef struct StackRecord 
2 {
3     int capacity;    //棧大小
4     int TopOfStack;     //棧頂
5     int *Array;         //陣列地址
6 }Stack;

 

對空棧的pop和滿棧的push都將引起程式崩潰

 

建立棧,陣列實現

 建立空棧

1 void MakeEmpty(Stack *S)
2 {
3     S->TopOfStack = -1;
4 }

 

 

建立棧(不考慮記憶體申請失敗)

1 Stack* CreatStack(int MaxSize)
2 {
3     StackRecord *S = new StackRecord;
4     S->Array = new int[MaxSize];
5     S->capacity = MaxSize;
6     MakeEmpty(S);
7     return S;
8 }

 

 

 檢測是否為空棧

1 int IsEmpty(Stack *S)
2 {
3     return S->TopOfStack == -1;
4 }

 

 

檢測是否為滿棧

1 int IsFull(Stack *S)
2 {
3     return S->TopOfStack == MaxSize - 1;
4 }

 

 

進棧

1 void Push(int x, Stack *S)
2 {
3     if (IsFull(S))              //棧滿將丟擲異常
4         ;
5     else
6         S->Array[++S->TopOfStack] = x;
7   //S->TopOfStack++;
8 //S->Array[
TopOfStack] = x;
9 }

 

 

返回棧頂元素

1 int Top(Stack *S)
2 {
3     if (!IsEmpty(S))
4         return S->Array[S->TopOfStack];
5     else
6         ;
7 }

 

 

出棧

1 void Pop(Stack *S)
2 {
3     if (IsEmpty(S))
4         ;
5     else
6         S->TopOfStack--;
7 }

 

 

棧的遍歷

以遍歷陣列的方式遍歷即可

 

釋放棧

1 void DisposeStack(Stack *S)
2 {
3     if (S != NULL)
4     {
5         delete S->Array;
6         delete S;
7     }
8 }

 

 

5.鏈棧與順序棧

順序棧比鏈棧操作簡便,避免了指標,但對儲存空間利用效率低,大小固定,不如連結串列實現靈活

陣列實現時,宣告的棧太小,會造成棧溢位,太大則造成空間浪費

 

6.棧的應用

挖坑待填

 

 

參考資料:《資料結構與演算法分析——C語言描述》    Mark Allen Weiss