2024年11月27日 星期三

deque 20 例

 deque 的 20 個實際應用範例


1. FIFO 佇列

模擬簡單的先進先出佇列:

from collections import deque

queue = deque()
queue.append("A")  # 加入佇列
queue.append("B")
queue.append("C")

print(queue.popleft())  # 移除並返回最早進入的元素,輸出: A
print(queue)            # 剩下的佇列: deque(['B', 'C'])


2. LIFO 堆疊

模擬簡單的後進先出堆疊:

from collections import deque

stack = deque()
stack.append("A")  # 加入堆疊
stack.append("B")
stack.append("C")

print(stack.pop())  # 移除並返回最後加入的元素,輸出: C
print(stack)        # 剩下的堆疊: deque(['A', 'B'])


3. 廣度優先搜尋 (BFS)

用 deque 高效實現 BFS:

from collections import deque

graph = {1: [2, 3], 2: [4, 5], 3: [6], 4: [], 5: [], 6: []}

def BFS(start):
    queue = deque([start])
    visited = set()

    while queue:
        node = queue.popleft()  # 取出當前節點
        if node not in visited:
            print(node, end=" ")  # 處理節點
            visited.add(node)
            queue.extend(graph[node])  # 加入鄰居節點

BFS(1)  # 輸出: 1 2 3 4 5 6


4. 滑動視窗問題

使用固定長度的 deque 計算滑動視窗的總和:

from collections import deque

def sliding_window_sum(arr, k):
    window = deque()
    window_sum = 0

    for i, num in enumerate(arr):
        window.append(num)
        window_sum += num

        if len(window) > k:  # 視窗超過大小時移除左端
            window_sum -= window.popleft()

        if len(window) == k:  # 滿足視窗大小,輸出總和
            print(f"視窗 {list(window)} 的總和為 {window_sum}")

sliding_window_sum([1, 2, 3, 4, 5], 3)
# 輸出:
# 視窗 [1, 2, 3] 的總和為 6
# 視窗 [2, 3, 4] 的總和為 9
# 視窗 [3, 4, 5] 的總和為 12


5. 旋轉資料

使用 rotate 操作旋轉資料:

from collections import deque

dq = deque([1, 2, 3, 4, 5])
dq.rotate(2)  # 向右旋轉 2 步
print(dq)     # 輸出: deque([4, 5, 1, 2, 3])

dq.rotate(-3)  # 向左旋轉 3 步
print(dq)      # 輸出: deque([2, 3, 4, 5, 1])


6. 固定長度佇列

限制 deque 長度來儲存最近的 N 筆資料:

from collections import deque

dq = deque(maxlen=3)  # 限制長度為 3
dq.extend([1, 2, 3])
print(dq)  # 輸出: deque([1, 2, 3], maxlen=3)

dq.append(4)  # 超出長度時,自動移除左端元素
print(dq)     # 輸出: deque([2, 3, 4], maxlen=3)


7. 判斷回文

使用 deque 高效判斷字串是否為回文:

from collections import deque

def is_palindrome(string):
    dq = deque(string)
    while len(dq) > 1:
        if dq.popleft() != dq.pop():  # 左右兩端不相等則非回文
            return False
    return True

print(is_palindrome("level"))  # 輸出: True
print(is_palindrome("hello"))  # 輸出: False


8. 最近使用(LRU)快取

模擬最近使用快取(LRU Cache)的邏輯:

from collections import deque

cache = deque(maxlen=3)  # 限制快取長度為 3

def access_page(page):
    if page in cache:
        cache.remove(page)  # 如果已存在,移至最右端
    cache.append(page)
    print("目前快取:", list(cache))

access_page(1)
access_page(2)
access_page(3)
access_page(2)
access_page(4)
# 輸出:
# 目前快取: [1]
# 目前快取: [1, 2]
# 目前快取: [1, 2, 3]
# 目前快取: [1, 3, 2]
# 目前快取: [3, 2, 4]


9. 時間序列處理

管理時間序列資料,確保只保留最近的資料點:

from collections import deque
import time

timestamps = deque()

def add_event():
    now = time.time()
    timestamps.append(now)

def cleanup(threshold):
    while timestamps and timestamps[0] < time.time() - threshold:
        timestamps.popleft()

# 模擬事件
add_event()
time.sleep(1)
add_event()
time.sleep(2)
cleanup(2)  # 移除超過 2 秒的舊資料
print(timestamps)  # 只保留最近的事件


10. 模擬回合制遊戲

使用 deque 模擬玩家輪流行動:

from collections import deque

players = deque(["Player1", "Player2", "Player3", "Player4"])

while len(players) > 1:
    current = players.popleft()  # 當前玩家
    print(f"{current} 的回合")
    players.append(current)  # 加回隊尾(輪到下一位)

print(f"勝利者是: {players[0]}")


總結

deque 是一個功能強大且高效的資料結構,適合用於:

  • 佇列(FIFO)
  • 堆疊(LIFO)
  • 限制長度的快取
  • 時間序列與回文檢查等

deque 的另外 10 個應用範例,涵蓋更多實際場景,進一步展現其靈活性與高效能:


1. 模擬循環隊列

適合處理多輪循環的場景,例如音樂播放列表:

from collections import deque

playlist = deque(["Song1", "Song2", "Song3", "Song4"])
for _ in range(6):  # 循環播放 6 次
    current_song = playlist.popleft()
    print(f"播放: {current_song}")
    playlist.append(current_song)  # 加回隊尾


2. 節點層次遍歷

用於樹的層次遍歷(Level Order Traversal):

from collections import deque

def level_order_traversal(tree):
    if not tree:
        return
    queue = deque([tree])
    while queue:
        node = queue.popleft()
        print(node["value"], end=" ")
        if node.get("left"):
            queue.append(node["left"])
        if node.get("right"):
            queue.append(node["right"])

# 測試二叉樹
tree = {
    "value": 1,
    "left": {"value": 2, "left": {"value": 4}, "right": {"value": 5}},
    "right": {"value": 3},
}
level_order_traversal(tree)  # 輸出: 1 2 3 4 5


3. 用作稀疏矩陣的列管理

使用 deque 儲存非零元素,進行矩陣壓縮與訪問:

from collections import deque

# 建立稀疏矩陣的行
sparse_row = deque([(1, 3), (4, 7)])  # (索引, 值)

# 新增非零元素
sparse_row.append((5, 2))
print("行內容:", sparse_row)

# 遍歷非零元素
for idx, val in sparse_row:
    print(f"索引: {idx}, 值: {val}")


4. 延遲工作處理

模擬一個延遲任務處理系統:

from collections import deque
import time

tasks = deque()

# 加入任務
tasks.append((time.time() + 2, "Task1"))  # 延遲 2 秒執行
tasks.append((time.time() + 4, "Task2"))  # 延遲 4 秒執行

# 處理任務
while tasks:
    current_time = time.time()
    task_time, task_name = tasks[0]
    if current_time >= task_time:
        print(f"執行: {task_name}")
        tasks.popleft()
    time.sleep(1)


5. 計算最近 N 次的平均值

維護一個固定長度的視窗來計算平均值:

from collections import deque

window = deque(maxlen=5)  # 固定視窗大小
nums = [10, 20, 30, 40, 50, 60]

for num in nums:
    window.append(num)
    print(f"最近 {len(window)} 個數字: {list(window)}, 平均值: {sum(window) / len(window)}")


6. 文字分解與重組

將句子分解為單詞,並進行處理:

from collections import deque

sentence = "Python deque is very useful"
words = deque(sentence.split())  # 分解句子
print("原始順序:", words)

# 反向重組句子
words.reverse()
print("反向順序:", " ".join(words))


7. 模擬雙向遊戲角色移動

用來記錄角色左右移動的步伐:

from collections import deque

steps = deque()
steps.append("left")
steps.append("right")
steps.append("left")
steps.appendleft("start")  # 起始位置

print("步驟順序:", list(steps))
steps.pop()  # 移除最後一步
print("剩餘步驟:", list(steps))


8. 解碼括號表達式

用 deque 處理括號展開問題:

from collections import deque

def decode_expression(expression):
    stack = deque()
    for char in expression:
        if char == ')':
            temp = ""
            while stack and stack[-1] != '(':
                temp = stack.pop() + temp
            stack.pop()  # 移除 '('
            stack.append(temp[::-1])  # 範例操作:反轉括號內內容
        else:
            stack.append(char)
    return "".join(stack)

print(decode_expression("a(bc)d"))  # 輸出: abcd


9. 用於序列優化

計算滑動最小值:

from collections import deque

def sliding_window_minimum(nums, k):
    dq = deque()
    result = []

    for i, num in enumerate(nums):
        while dq and dq[0] < i - k + 1:  # 移除超出視窗範圍的索引
            dq.popleft()
        while dq and nums[dq[-1]] > num:  # 移除無效的索引
            dq.pop()
        dq.append(i)  # 新增當前索引
        if i >= k - 1:  # 開始輸出最小值
            result.append(nums[dq[0]])

    return result

print(sliding_window_minimum([10, 2, 4, 8, 6, 1], 3))  # 輸出: [2, 2, 4, 1]


10. 日誌系統記錄

用來儲存最近的 N 條日誌:

from collections import deque

logs = deque(maxlen=5)  # 只保留最近 5 條日誌

def log_event(event):
    logs.append(event)
    print("目前日誌:", list(logs))

log_event("啟動系統")
log_event("加載模組")
log_event("用戶登入")
log_event("用戶登出")
log_event("關閉系統")
log_event("重新啟動")  # 最舊日誌自動移除

沒有留言:

張貼留言