2026年1月19日 星期一

Dynamic Binary Search Tree Algorithm (動態二元搜尋樹演算法)

 Dynamic Binary Search Tree Algorithm (動態二元搜尋樹演算法)

 Dynamic Binary Search Tree Algorithm (動態二元搜尋樹演算法) 是對傳統二元搜尋樹的一種優化。在 RFID 防碰撞中,它通常結合了 「回退機制」「動態調整查詢深度」,以減少無謂的查詢(Idle Slots)。

與固定深度的搜尋不同,動態搜尋會根據碰撞發生的位元位置,直接跳過不必要的節點。


演算法邏輯解析

  1. 動態分裂 (Splitting):

    當發生碰撞時,演算法不會停止,而是根據碰撞發生的位元(最高有效位),將目前的標籤群組動態地切割。

  2. 與固定搜尋的差異:

    在某些動態版本中,如果閱讀器檢測到連續多位元沒有碰撞,它會動態增加查詢位元的長度(跳過中間節點),從而減少通訊來回的次數。

  3. 回退 (Backtracking):

    當左子樹(例如以 0 開頭的分支)處理完畢後,演算法會根據堆疊(Stack)自動回退到右子樹(以 1 開頭的分支)。


總結比較

演算法防止碰撞原理適用場景
Static Tree固定位元逐一查詢標籤數量少且固定
Dynamic Tree根據碰撞位置跳躍或調整深度標籤數量變動大、ID 分布不均
CDMA/DSSS碼分多址,同時發送高度併發、對即時性要求高
Slotted ALOHA隨機時槽,機率碰撞標籤硬體成本極低




import tkinter as tk
from tkinter import messagebox
import random

class DynamicBinaryTreeSim:
    def __init__(self, root):
        self.root = root
        self.root.title("Dynamic Binary Search Tree RFID 防碰撞模擬")
        self.root.geometry("700x700")

        self.tags = []
        self.identified = []
        self.stack = []  # 存儲查詢前綴
        self.query_count = 0
        
        self.setup_ui()
        self.reset_sim()

    def setup_ui(self):
        tk.Label(self.root, text="Dynamic Binary Search Tree Algorithm", font=("Arial", 16, "bold")).pack(pady=10)
        
        # 標籤顯示區
        self.tag_info = tk.Label(self.root, text="", font=("Consolas", 12), fg="green")
        self.tag_info.pack(pady=5)

        # 狀態統計
        self.stat_label = tk.Label(self.root, text="查詢次數: 0 | 已識別: 0", font=("Arial", 10))
        self.stat_label.pack()

        # 畫布:動態樹狀示意圖
        self.canvas = tk.Canvas(self.root, width=600, height=250, bg="white", highlightthickness=1)
        self.canvas.pack(pady=10)

        # 日誌
        self.log_box = tk.Listbox(self.root, width=80, height=15, font=("Consolas", 10))
        self.log_box.pack(pady=10)

        # 控制鈕
        btn_frame = tk.Frame(self.root)
        btn_frame.pack(pady=10)
        
        self.btn_next = tk.Button(btn_frame, text="下一步 (Query)", width=15, bg="#fff9c4", command=self.process_step)
        self.btn_next.pack(side=tk.LEFT, padx=10)
        
        tk.Button(btn_frame, text="重新開始 (Reset)", width=15, command=self.reset_sim).pack(side=tk.LEFT, padx=10)

    def reset_sim(self):
        # 隨機產生 4 個不重複的 4-bit ID (增加深度感)
        all_ids = [format(i, '04b') for i in range(16)]
        self.tags = sorted(random.sample(all_ids, 4))
        
        self.stack = [""] # 從根節點開始
        self.identified = []
        self.query_count = 0
        
        self.update_stats()
        self.log_box.delete(0, tk.END)
        self.canvas.delete("all")
        self.log_box.insert(tk.END, "--- 系統重置:等待掃描 ---")
        self.tag_info.config(text=f"目標標籤: {', '.join(self.tags)}")
        self.btn_next.config(state=tk.NORMAL)

    def update_stats(self):
        self.stat_label.config(text=f"查詢次數: {self.query_count} | 已識別: {len(self.identified)}/{len(self.tags)}")

    def draw_node(self, prefix, x, y, level, is_collision=False):
        color = "red" if is_collision else "lightblue"
        r = 20
        self.canvas.create_oval(x-r, y-r, x+r, y+r, fill=color)
        self.canvas.create_text(x, y, text=prefix if prefix != "" else "Root", font=("Arial", 8))

    def process_step(self):
        if not self.stack:
            messagebox.showinfo("完成", f"識別結果: {self.identified}")
            self.btn_next.config(state=tk.DISABLED)
            return

        prefix = self.stack.pop()
        self.query_count += 1
        self.update_stats()

        # 模擬標籤響應
        matches = [t for t in self.tags if t.startswith(prefix)]
        
        self.log_box.insert(tk.END, f"Round {self.query_count}: 查詢前綴 [{prefix}]")
        
        # 繪圖座標 (簡單示意)
        level = len(prefix)
        x = 300 + (len(self.stack) * 30) # 隨意位移避免重疊
        y = 40 + (level * 50)

        if len(matches) > 1:
            # 碰撞:動態分裂
            self.log_box.insert(tk.END, f"  [!] 碰撞: 符合數 {len(matches)}。分裂為 {prefix}0 與 {prefix}1")
            self.log_box.itemconfig(tk.END, fg="red")
            self.draw_node(prefix, x, y, level, True)
            
            # 動態樹優化:先放 1 再放 0 (深度優先)
            self.stack.append(prefix + "1")
            self.stack.append(prefix + "0")
            
        elif len(matches) == 1:
            # 成功識別
            tag = matches[0]
            self.log_box.insert(tk.END, f"  [V] 成功: 識別出標籤 {tag}")
            self.log_box.itemconfig(tk.END, fg="blue")
            self.draw_node(prefix, x, y, level, False)
            if tag not in self.identified:
                self.identified.append(tag)
        else:
            # 空閒
            self.log_box.insert(tk.END, "  [-] 空閒: 無標籤響應")
            self.log_box.itemconfig(tk.END, fg="gray")

        self.log_box.see(tk.END)

if __name__ == "__main__":
    root = tk.Tk()
    app = DynamicBinaryTreeSim(root)
    root.mainloop()





沒有留言:

張貼留言

Dynamic Framed Slotted ALOHA (DFSA) 防撞方法

 Dynamic Framed Slotted ALOHA (DFSA)防撞方法 DFSA 的核心邏輯: 動態框長 (Dynamic Frame Size) :閱讀器會根據上一輪的結果(碰撞次數、空閒次數)來 動態調整 下一輪的時槽數(框長 $L$ )。 效率優化 :當標籤很多時...