# 1.1 - Stack

### 1. 介紹

堆疊(Stack)是一種特殊的抽象資料結構，可以用鏈結串列(Link List)或陣列(Array)來表示，堆疊的特點是只允許在Link List或是Array的頂端(Top)進行存取，具有先進後出(FILO, First-In-Last-Out)或後進先出(LIFO, Last-In-First-Out)的特性。

![](https://2769815795-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LGckN3OAfinKuVIrkMj%2F-LGeSRCLyGzxFvh8HqlY%2F-LGeSgvUuWVE8FMubL2B%2Fezgif.com-video-to-gif.gif?alt=media\&token=9ec70955-00c2-42e3-837e-ae2d8a176a28)

### 2. 基本操作

* Pop(): 從堆疊的頂端(Top)取出資料。
* Push(): 將資料放到堆疊的頂端。
* IsEmpty(): 檢查是否堆疊為空。
* IsFull(): 檢查堆疊是否已滿。(當使用Array製作堆疊時需注意是否已滿。)

#### 2.1 以Link List來表示堆疊的基本操作。

1. Pop(): 回傳top指標(指向堆疊的頂端)的資料。

```
int pop(){
    if (IsEmpty() == 1){    //檢查是否堆疊為空
        printf("The stack is empty.\n");
        return 0;
    }
    else{
        stack *output = top;
        top = top->next;    //將top指向下一個node
        return output->Data; //回傳頂端資料
    }
    return -1;
}
```

2\. Push(data): 將資料放到堆疊的頂端。

```
void push(int data){
    // 要求空間存取新資料
    stack *new_node = (stack *)malloc(sizeof(stack));
    
    // 將資料放到新的node中
    new_node->Data = data;
    new_node->next = NULL;
    
    if (IsEmpty() == 1){ //如果堆疊為空，新放入的資料即為頂端
        top = new_node;
    }
    else{
        new_node->next = top; //原本的top變成舊的資料，所以將新node指向舊的資料(top)
        top = new_node;     //assign新的node為top
    }
}
```

3\. 輸出結果範例:

```
Push: 1, 2,	3
Stack: 3, 2, 1
Push: 4, 5
Stack: 5, 4, 3,	2, 1	
Pop, the top is: 5
Pop, the top is: 4
Stack: 3, 2, 1
```

完整程式碼：<https://github.com/gary30404/Data-Structure/blob/master/1/1.1/stack_in_linklist.c>

#### 2.2 以Array來表示堆疊的基本操作。和Link List不同的是，使用Array必須先宣告堆疊的大小，所以堆疊有可能會被填滿而無法再加入資料。

1. 設定堆疊的大小

```
// define data type
typedef struct stack{
    int *Data; // 陣列
    int top;   //頂端位置
    int MAX_SIZE; 
}stack;
```

2\. Pop(): 回傳top指向堆疊的頂端的資料。

```
int pop(stack *st){
    if (IsEmpty(st) == 1){
        printf("The stack is empty.\n");
        return 0;
    }
    else{
        int output = st->Data[st->top];
        st->Data[st->top] = 0; //設定為0代表此位置沒有存資料
        st->top--; //top向下一層
        return output;
    }
    return -1;
}
```

3\. Push(data): 將資料放到堆疊的頂端。

```
void push(stack *st, int data){

    if (IsFull(st) == 1){
        printf("The stack is full.\n");
    }
    else{
        st->Data[++st->top] = data; //先將top往上加一層後填入資料
    }
}
```

4\. 輸出結果範例:

```
Push: 1, 2,	3
Stack: 3, 2, 1
Push: 4, 5
Stack: 5, 4, 3,	2, 1	
Pop, the top is: 5
Pop, the top is: 4
Stack: 3, 2, 1
```

完整程式碼：<https://github.com/gary30404/Data-Structure/blob/master/1/1.1/stack_in_array.c>

### 3. 應用（前、中、後序）

#### 3.1 Infix(中序)

格式: **operand1** `operator` **operand2**

e.g. `a+(b/c)`, `x*y+z`

缺點: 編譯器使用中序式做計算非常麻煩，因為必須要考慮運算子(operator)的優先順序和結合性，導致可能要來回掃描多次才能計算出結果。

#### 3.2 Postfix(後序)

格式: **operand1**  **operand2** `operator`

e.g. `ab+`

優點: 編譯器只需由左至右掃描一次即可球出結果，已免除掉運算子的優先順序和結合性。

#### 3.3 Prefix(前序)

格式: `operator` **operand1**  **operand2**

e.g. `+ab`

優點: 編譯器只需由右至左掃描一次即可球出結果，已免除掉運算子的優先順序和結合性。

### 4. 運算元之高低順序

1. 括號()
2. 負號-
3. ＾
4. \*, /
5. +, -
6. \>, <, ==, >=, ...
7. Logic
8. AND, OR
9. \=

### 5. 轉換法則

* 將中序式轉成後(前)序式

1. 在中序式加上完整的括號配對
2. 將運算元**取代最近的右(左)括號**
3. 刪去左(右)括號，其餘由左而右寫出即可得出後序式

![](https://2769815795-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LGckN3OAfinKuVIrkMj%2F-LGnbFeXdrwPKB6QRKaa%2F-LGnjQTL5iynid8OQOOv%2Fezgif.com-video-to-gif-2.gif?alt=media\&token=63c07253-d5a5-4168-bac7-0b71482a4548)

* 中序轉後序演算法

1. 由左至右掃描運算式
2. 若遇到運算元則將其印出
3. 若遇到運算子，考慮以下情況:
   1. 若stack為空，push()
   2. 若stack內有其他運算子，和頂端的運算子比較優先順序，stack頂端優先順序較小則push()；stack頂端優先順序較大則pop()，直到stack頂端優先順序小於當前的運算子，或stack為空。
   3. 當遇到`)`時，pop()堆疊內的資料，直到`(`。
4. 掃完運算式後，將stack清空。

完整程式碼：<https://github.com/gary30404/Data-Structure/blob/master/1/1.3/infix2postfix.c>

* 後序法計算運算式演算法

1. 將運算元push()到stack中，直到遇到運算子。
2. 從stack中pop()出兩個運算元，並使用當前運算子做計算得出結果後在push()回stack中。
3. 重複以上步驟，直到掃描完運算式。
