重學資料結構之棧

TM0831發表於2020-05-06

一、前言簡介

  資料結構課程是一門重要的計算機基礎課程,而我本人在上學期間真是沒學好這門課, 聽課總是聽得雲裡霧裡的,寫起程式碼來也不知道如何編寫和運用這些資料結構,以致於後來考試也只能是低分飄過,所以現在就需要花時間重新學習一下資料結構了!

  為了能夠更好地學習和掌握資料結構,除了學習和理解相應的概念,我還會找幾個題目並用所學的資料結構來解決問題,相應的問題和程式碼也會一併記錄在部落格中。

 

二、棧的概念

1.基本概念

  棧(stack)又被稱為堆疊,是一種儲存資料元素的容器。棧作為一種資料結構,是一種只能在一端進行插入和刪除操作的特殊線性表,允許進行插入和刪除操作的一端叫做棧頂(top),另一端則叫做棧底(bottom),插入元素一般稱為進棧(PUSH),刪除元素一般稱為出棧(POP)。

  棧按照後進先出的原則(LIFO, Last In First Out)儲存資料,後存入的元素會先被取出來使用。存入棧中的元素相互之間並沒有任何具體的關係,只有存入的時間先後順序,而沒有元素的前後順序或者元素的位置等概念。

2.抽象資料型別

  棧的基本操作一個封閉的資料集合,在一個棧裡需要實現將元素壓入棧中即進棧、從棧中彈出元素即出棧、返回最後一個插入棧中的元素、獲取棧中元素的數量等方法,下面就是一個棧的抽象資料型別描述:

ADT Stack:

  Stack(self)  # 建立一個空棧

  empty(self)  # 判斷棧是否為空

  push(self, x)  # 將元素壓入棧中

  pop(self)  # 從棧中彈出元素

  peek(self)  # 返回最後一個插入的元素

  size(sellf)  # 獲取棧中元素的數量

3.用 Python 實現

  在 Python 中沒有棧這種資料結構,但我們可以藉助 list 來實現,用 list 來存放資料,並實現一個棧所需要的各種方法,具體程式碼如下:

 1 # 自定義棧
 2 class MyStack:
 3     def __init__(self):
 4         self.data = []
 5 
 6     def push(self, x):
 7         """
 8         將資料壓入棧中
 9         :param x: 需要插入的元素
10         :return: 
11         """
12         self.data.append(x)
13 
14     def pop(self):
15         """
16         從棧中彈出元素
17         :return: 彈出的元素
18         """
19         if not self.empty():
20             ret, self.data = self.data[-1], self.data[:-1]
21             return ret
22         return None
23 
24     def empty(self):
25         """
26         判斷棧是否為空
27         :return: 棧空--True,非空--False
28         """
29         return len(self.data) == 0
30 
31     def size(self):
32         """
33         獲取棧中元素的數量
34         :return: 
35         """
36         return len(self.data)
37 
38     def peek(self):
39         """
40         返回最後一個插入的元素
41         :return: 最後一個插入的元素
42         """
43         if not self.empty():
44             return self.data[-1]
45         return None

 

三、棧的應用

1.進位制轉換

1)問題描述

  輸入一個任意的十進位制正整數,將其轉化成相應的二進位制、八進位制和十六進位制的數。

2)解決思路

  這裡首先需要介紹一個公式:

N = (N div d) * d + N mod d

  其中 div 表示整除,mod 表示求餘。例如當輸入的正整數 N 為777,輸出的進位制是八進位制時,計算過程如下:

N      N div 8    N mod 8

777   97       1

97     12       1

12    1     4

1      0     1  

  在進行進位制轉換的時候,我們就可以將每次求餘的結果儲存在棧中,最後將棧中的數依次取出,就是轉換後的結果了,例如十進位制的777轉換成八進位制就是1411。

3)程式碼實現

  如何用程式碼來解決這個問題?一個思路就是將每次求餘的結果儲存在棧中,而整除的結果則用來進行下一步的計算,直到這個整除的結果為0,表明計算結束,再出棧中依次取出元素,得到的結果就是轉換成相應進位制後的數。具體程式碼如下:

 1 def solution(n: int, scale: int):
 2     """
 3     進位制轉換
 4     :param n: 正整數
 5     :param scale: 進位制
 6     :return:
 7     """
 8     stack = MyStack()
 9     # 迴圈計算
10     while n // scale >= 0 and n > 0:
11         stack.push(n % scale)
12         n = n // scale
13     # 輸出
14     while not stack.empty():
15         print(stack.pop(), end="")

2.括號匹配

1)問題描述

  輸入一個字串,裡面可能有“()”、“[]”和“{}”三種括號,編寫程式檢查該字串中的括號是否成對出現。

2)解決思路

  遍歷這個字串,用棧來存放每次遍歷的元素,如果遍歷的元素和棧頂的括號是配對的,則進行出棧操作將棧頂元素彈出,反之若不配對,則進行入棧操作將該元素插入到棧中。等遍歷結束後,若棧為空,則表明該字串中的括號都是成對出現的,若棧不為空,則表明有括號不匹配。

3)程式碼實現

 1 def solution(input_string: str):
 2     """
 3     判斷輸入的字元中的括號是否成對出現
 4     :param input_string: 輸入字串
 5     :return:
 6     """
 7     def match(c1: str, c2: str):
 8         """
 9         判斷兩個括號是否匹配
10         :param c1: 
11         :param c2: 
12         :return: 
13         """
14         if c1 == "(" and c2 == ")":
15             return True
16         elif c1 == "[" and c2 == "]":
17             return True
18         elif c1 == "{" and c2 == "}":
19             return True
20         else:
21             return False
22 
23     stack = MyStack()
24     for i in range(len(input_string)):
25         if stack.empty():
26             # 棧空直接入棧
27             stack.push(input_string[i])
28         else:
29             # 棧非空時進行比較
30             if match(stack.peek(), input_string[i]):
31                 stack.pop()
32             else:
33                 stack.push(input_string[i])
34     print("匹配!") if stack.empty() else print("不匹配!")

相關文章