1. 程式人生 > >資料結構 - 棧和佇列

資料結構 - 棧和佇列

資料結構 - 棧和佇列

介紹

  • 棧和佇列是兩種很簡單, 但也很重要的資料結構, 在之後的內容也會用到的
  • 棧的特點就是FILO(first in last out)
  • 而佇列則是FIFO(first in first out)

棧和佇列也是列表

  • 棧和佇列都可以認為是連結串列, 只是插入刪除的方式做了改變
  • 棧的插入刪除都在尾部, 如果是頭插法的話, 則是在頭部
  • 佇列的插入在尾部, 刪除在頭部

棧的兩種實現方式

陣列

  • 第一種 - 陣列, 對於知道了棧最大長度的情況, 我建議用陣列
 
 1 #include<bits/stdc++.h>
 2 using
namespace std; 3 const int MaxLength = 10000 + 20; 4 5 struct Stack { 6 int s[MaxLength]; 7 int index; 8 9 Stack():index(0){} 10 bool Empty(){ return index == 0; } 11 void Push(int d){ s[index++] = d; } 12 void Pop(){ 13 if (index) --index; 14 else printf("
Stack is Empty!\n"); 15 } 16 int Top(){ 17 if (index) return s[index - 1]; 18 else { 19 printf("Stack is Empty!!!\n"); 20 return -1; 21 } 22 } 23 void Clear(){ index = 0; } 24 void Print() { 25 for (int i = 0; i < index - 1; i++) 26 printf("%d ", s[i]); 27 if (index) printf("%d\n", s[index - 1]); 28 } 29 }; 30 31 int main () { 32 int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 33 Stack myStack; 34 for (int i = 0; i < 10; i++) myStack.Push(a[i]); 35 36 myStack.Print(); 37 myStack.Push(11); 38 myStack.Print(); 39 printf("top = %d\n", myStack.Top()); 40 myStack.Pop(); 41 myStack.Pop(); 42 myStack.Pop(); 43 myStack.Print(); 44 myStack.Clear(); 45 myStack.Pop(); 46 myStack.Top(); 47 return 0; 48 }

 

連結串列

  • 第二種 - 連結串列, 對於不知道最大長度情況可以用
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 struct Node {
 5     int data;
 6     Node *next;
 7     Node(int d, Node *nxt = nullptr):data(d), next(nxt){}
 8 };
 9 
10 ///建立棧, 並用頭插法插入dat的前n個元素
11 Node* Create(int n, int dat[]) {
12     Node *head = new Node(-1);
13 
14     for (int i = 0; i < n; i++) {
15         head -> next = new Node(dat[i], head -> next);
16     }
17     return head;
18 }
19 
20 ///在棧的頭部新增dat
21 void Push(Node *head, int dat) {
22     head -> next = new Node(dat, head -> next);
23 }
24 
25 ///判斷棧是否為空
26 bool Empty(Node *head) {
27     return head -> next == nullptr;
28 }
29 
30 ///彈出棧的第一個元素-棧頂元素
31 void Pop(Node *head) {
32     if (head -> next)   head -> next = head -> next -> next;
33     else    printf("棧已為空, 無法再彈出元素!\n");
34 }
35 
36 ///返回棧頂元素, 不刪除
37 int Top(Node *head) {
38     if (head -> next)   return head -> next -> data;
39     else    printf("棧已為空, 無棧頂元素!\n");
40 }
41 
42 ///清空棧
43 void Clear(Node *head) {
44     head -> next = nullptr;
45 }
46 
47 ///輸出棧, 由於是頭插法, 所以這裡用一下遞迴
48 ///遞迴其實也用到了棧
49 void Print(Node *head) {
50     if (head -> next) {
51         Print(head -> next);
52         printf(" %d", head -> data);
53     } else  printf("%d", head -> data);
54 }
55 
56 ///用這個函式補一個回車
57 void PrintStack(Node *head) {
58     Print(head -> next);
59     printf("\n");
60 }
61 
62 int main () {
63     int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
64     Node *head = Create(10, a);
65     PrintStack(head);
66     Push(head, 11);
67     PrintStack(head);
68     printf("top = %d\n", Top(head));
69     Pop(head);
70     Pop(head);
71     Pop(head);
72     PrintStack(head);
73     Clear(head);
74     Pop(head);
75     Top(head);
76     return 0;
77 }

 

佇列的兩種實現方式

陣列

  • 第一種, 陣列, 在知道佇列最大長度時, 使用陣列會很簡單
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int MaxLength = 10000 + 20;
 4 
 5 struct Queue {
 6     int myQueue[MaxLength];
 7     int head, tail;
 8 
 9     Queue():head(0), tail(0){}
10 
11     bool Empty() {
12         return head == tail;
13     }
14 
15     void Push(int dat) {
16         myQueue[tail++] = dat;
17     }
18 
19     void Pop() {
20         if (head != tail)   head++;
21         else    printf("This Queue is Empty!!\n");
22     }
23 
24     void Clear() {
25         head = tail = 0;
26     }
27 
28     int Front() {
29         if (!Empty())   return myQueue[head];
30         else    printf("The Queue is Empty!\n");
31     }
32 
33     void Print() {
34         if (Empty())    printf("Queue is Empty!!!\n");
35         else {
36             for (int i = head; i < tail - 1; i++)   printf("%d ", myQueue[i]);
37             printf("%d\n", myQueue[tail - 1]);
38         }
39     }
40 };
41 
42 int main () {
43     int a[10] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 4};
44     Queue Q;
45     for (int i = 0; i <10; i++)    Q.Push(a[i]);
46     Q.Print();
47     printf("front is : %d\n", Q.Front());
48 
49     Q.Pop();    Q.Pop();    Q.Pop();
50     Q.Print();
51 
52     Q.Clear();
53     Q.Print();
54 
55     return 0;
56 }

 

連結串列

  • 第二種, 連結串列, 在不知道佇列最大長度時可以使用, 我覺得很麻煩
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 struct Node {
 5     int data;
 6     Node *next;
 7     Node(int d, Node *nxt = nullptr):data(d), next(nxt){}
 8 };
 9 
10 Node* CreateQueue(int n, int dat[]) {
11     Node *head = new Node(-1);
12     Node *temp = head;
13 
14     for (int i = 0; i < n; i++) {
15         temp -> next = new Node(dat[i]);
16         temp = temp -> next;
17     }
18     return head;
19 }
20 
21 void Push(Node *head, int dat) {
22     Node *temp = head;
23     while (temp -> next)    temp = temp -> next;
24     temp -> next = new Node(dat);
25 }
26 
27 bool Empty(Node *head) {
28     return head -> next == nullptr;
29 }
30 
31 void Pop(Node *head) {
32     if (head -> next)   head -> next = head -> next -> next;
33     else printf("This Queue is Empty!\n");
34 }
35 
36 void Clear(Node *head) {
37     head -> next = nullptr;
38 }
39 
40 int Front(Node *head) {
41     if (head -> next)   return head -> next -> data;
42     else    printf("This Queue is Empty!!!\n");
43 }
44 
45 void Print(Node *head) {
46     Node *temp = head -> next;
47     if (temp) {
48         while (temp -> next) {
49             printf("%d ", temp -> data);
50             temp = temp -> next;
51         }
52         printf("%d\n", temp -> data);
53     } else  printf("Queue is Empty!\n");
54 }
55 
56 int main () {
57     int a[10] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 4};
58     Node *Q = CreateQueue(10, a);
59     Print(Q);
60     printf("Queue is Empty? : %s\n", Empty(Q) ? "true" : "false");
61     while (!Empty(Q))   Pop(Q);
62     Print(Q);
63     for (int i = 0; i < 10; i++)    Push(Q, a[i]);
64     Print(Q);
65     return 0;
66 }

 

小結

  • 對於一個慣用陣列的我來說, 我當然是喜歡用陣列了, 然而在實際上, 我會直接用STL裡面的queue, 棧的話, 我還用得比較少, 佇列用得比較多
  • 從這個碼量都看得出來, 陣列實現的棧和佇列實在是非常的簡單, 所以我覺得只看陣列的就夠了