最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于Python實現(xiàn)的單詞統(tǒng)計與查找分析工具

 更新時間:2026年01月22日 09:20:53   作者:.笑對人生.  
本文介紹了單詞統(tǒng)計與查找分析工具的設(shè)計與實現(xiàn),該工具支持三種查找策略,可計算文本中的單詞總數(shù)、唯一單詞數(shù)和平均查找長度(ASL),工具采用Python開發(fā),包含核心算法層和GUI交互層,需要的朋友可以參考下

一、引言

單詞統(tǒng)計與查找分析工具是一款面向 “單詞統(tǒng)計 + 查找算法對比” 的可視化工具,核心目標是實現(xiàn)文本中單詞的標準化解析、多策略(順序查找 / 快排 + 二分 / 哈希表)統(tǒng)計,并計算關(guān)鍵指標(Total Words、Unique Words、ASL 平均查找長度)。本文將詳細講解該工具的開發(fā)過程以及Python代碼完整實現(xiàn)(原始版 + 擴展版)。

二、第一階段:需求分析與功能規(guī)劃

開發(fā)前先明確工具的核心目標與邊界,確保功能貼合 “數(shù)據(jù)結(jié)構(gòu)與算法實踐” 的場景需求:

1. 核心業(yè)務(wù)需求

  • 文本解析與單詞標準化:提取文本中的純字母單詞(跳過數(shù)字 / 符號),統(tǒng)一轉(zhuǎn)為小寫,支持#作為文本結(jié)束符;
  • 多查找策略支持
    • 策略 1:基于線性表的順序查找,統(tǒng)計單詞頻次;
    • 策略 2:線性表快速排序后執(zhí)行二分查找,統(tǒng)計單詞頻次;
    • 策略 3:基于 Time33 哈希函數(shù)的哈希表(鏈地址法)查找,統(tǒng)計單詞頻次;
  • 關(guān)鍵指標計算
    • Total Words:解析出的單詞總數(shù)(含重復);
    • Unique Words:唯一單詞數(shù);
    • ASL(Average Search Length):平均查找長度(算法效率核心指標);
  • 可視化交互:GUI 界面操作(無需命令行),實時反饋輸入狀態(tài),清晰展示統(tǒng)計結(jié)果。

2. 非功能需求

  • 易用性:實時提示輸入字符數(shù)、#結(jié)束符檢測;策略切換即時反饋,結(jié)果格式化展示;
  • 魯棒性:處理空文本、超長單詞、無字母文本等邊界場景,避免崩潰;
  • 可對比性:三種策略的核心邏輯解耦,便于對比不同查找算法的效率(ASL);
  • 性能適配:哈希表大小固定為 1009(質(zhì)數(shù),減少哈希沖突),線性表最大容量限制為 10000(適配常規(guī)文本解析場景)。

三、第二階段:技術(shù)選型

結(jié)合 “算法實踐 + 可視化交互” 的核心需求,選擇輕量、易理解的技術(shù)棧:

技術(shù) / 模塊選型理由
Python 3.8+語法簡潔,數(shù)據(jù)結(jié)構(gòu)(列表、字典)原生支持,算法實現(xiàn)直觀,適合教學 / 實踐場景
tkinter + ttkPython 內(nèi)置 GUI 庫,無需額外安裝,足夠支撐輕量交互界面;ttk 提升控件美觀度
原生數(shù)據(jù)結(jié)構(gòu)(列表)模擬線性表、哈希表(鏈地址法),無需第三方庫,降低學習 / 使用成本
Time33 哈希函數(shù)簡單高效的字符串哈希算法(h = h*33 + ord(char)),分布均勻,沖突率低
快速排序 + 二分查找經(jīng)典排序 / 查找算法組合,對比順序查找體現(xiàn) “有序表 + 二分” 的效率優(yōu)勢

四、第三階段:架構(gòu)設(shè)計

采用 “模塊化 + 面向?qū)ο?rdquo; 混合設(shè)計,核心分為三層,確保邏輯解耦、便于維護:

classDiagram
    direction LR
    "全局常量層" --> "核心算法層" : 依賴常量配置
    "核心算法層" --> "GUI交互層" : 提供算法調(diào)用
    "GUI交互層" --> "核心算法層" : 傳遞業(yè)務(wù)數(shù)據(jù)
    
    class 全局常量層 {
        MAX_LINEAR_SIZE: int = 10000
        HASH_SIZE: int = 1009
        MAX_WORD_LEN: int = 50
    }
    
    class 核心算法層 {
        +normalize(token, pos): (bool, str)  # 單詞標準化
        +my_hash(word): int  # Time33哈希
        +linear_search(linear_list, word): (bool, int)  # 順序查找
        +quick_sort(linear_list, low, high)  # 快速排序
        +binary_search(linear_list, word): (bool, int)  # 二分查找
    }
    
    class GUI交互層 {
        -root: tk.Tk
        -strategy_var: tk.StringVar
        +_setup_ui()  # 搭建UI
        +_on_text_changed(event)  # 文本輸入監(jiān)控
        +_on_strategy_toggled()  # 策略切換
        +_on_analyze_clicked()  # 分析按鈕邏輯
        +_update_result(text, color)  # 更新結(jié)果展示
    }

HTML代碼:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>單詞統(tǒng)計工具 - 架構(gòu)類圖</title>
    <!-- 引入Mermaid CDN -->
    <script src="https://cdn.jsdelivr.net/npm/mermaid@10.16.0/dist/mermaid.min.js"></script>
    <style>
        body {
            font-family: "Microsoft YaHei", Arial, sans-serif;
            padding: 20px;
            background: #f5f5f5;
        }
        .container {
            max-width: 1200px;
            margin: 0 auto;
            background: white;
            padding: 30px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        h1 {
            text-align: center;
            color: #333;
            margin-bottom: 30px;
        }
        /* 確保Mermaid代碼保留換行格式 */
        .mermaid {
            white-space: pre;
            font-family: monospace;
        }
    </style>
</head>
<body>
<div class="container">
    <h1>單詞統(tǒng)計與查找分析工具 - 架構(gòu)類圖</h1>
    <!-- Mermaid類圖代碼(直接放在mermaid容器中,保留原始格式) -->
    <div class="mermaid">
        classDiagram
        direction LR

        %% 層間關(guān)聯(lián)
        全局常量層 --> 核心算法層 : 依賴常量配置
        核心算法層 --> GUI交互層 : 提供算法調(diào)用
        GUI交互層 --> 核心算法層 : 傳遞業(yè)務(wù)數(shù)據(jù)

        %% 全局常量層
        class 全局常量層 {
        MAX_LINEAR_SIZE: int = 10000
        HASH_SIZE: int = 1009
        MAX_WORD_LEN: int = 50
        }

        %% 核心算法層
        class 核心算法層 {
        +normalize(token, pos): (bool, str) // 單詞標準化
        +my_hash(word): int // Time33哈希
        +linear_search(linear_list, word): (bool, int) // 順序查找
        +quick_sort(linear_list, low, high) // 快速排序
        +binary_search(linear_list, word): (bool, int) // 二分查找
        }

        %% GUI交互層
        class GUI交互層 {
        -root: tk.Tk
        -strategy_var: tk.StringVar
        +_setup_ui() // 搭建UI
        +_on_text_changed(event) // 文本輸入監(jiān)控
        +_on_strategy_toggled() // 策略切換
        +_on_analyze_clicked() // 分析按鈕邏輯
        +_update_result(text, color) // 更新結(jié)果展示
        }
    </div>
</div>

<script>
    // 初始化Mermaid,啟用自動加載
    mermaid.initialize({
        startOnLoad: true,
        theme: 'default',
        classDiagram: {
            fontSize: 14,
            nodeSpacing: 30,
            rankSpacing: 40
        }
    });
</script>
</body>
</html>

核心設(shè)計思路:

  1. 全局常量層:集中管理配置參數(shù)(如哈希表大小、線性表最大容量),便于統(tǒng)一修改;
  2. 核心算法層:純函數(shù)式設(shè)計,與 GUI 解耦,可獨立測試 / 復用(比如單獨調(diào)用算法函數(shù)驗證邏輯);
  3. GUI 交互層:面向?qū)ο蠓庋b,負責界面渲染、事件處理、業(yè)務(wù)邏輯串聯(lián)(調(diào)用算法 + 展示結(jié)果)。

五、第四階段:分模塊詳細開發(fā)

1. 全局常量層開發(fā)

定義工具的核心配置參數(shù),取值需兼顧 “場景適配 + 算法特性”:

常量名取值設(shè)計理由
MAX_LINEAR_SIZE10000限制線性表最大容量,避免極端文本導致內(nèi)存溢出,適配常規(guī)文本解析場景
HASH_SIZE1009選擇質(zhì)數(shù)作為哈希表大小(質(zhì)數(shù)能減少哈希沖突,1009 是接近 1000 的質(zhì)數(shù),平衡性能與內(nèi)存)
MAX_WORD_LEN50限制單詞最大長度,過濾異常超長字符串(如無分隔符的字母串)

2. 核心算法層開發(fā)

這是工具的 “算法核心”,所有函數(shù)均為純邏輯實現(xiàn),無 GUI 依賴,可獨立調(diào)用測試。

(1)單詞標準化函數(shù)(normalize)

解決 “文本中提取有效單詞” 的問題,核心需求:跳過非字母字符、提取連續(xù)字母、統(tǒng)一轉(zhuǎn)小寫。

def normalize(token: str, pos: list) -> tuple[bool, str]:
    # 跳過非字母字符(如數(shù)字、符號、空格)
    while pos[0] < len(token) and not token[pos[0]].isalpha():
        pos[0] += 1
    if pos[0] >= len(token):
        return False, ""
    
    # 提取連續(xù)字母并轉(zhuǎn)小寫(保證單詞格式統(tǒng)一)
    word = []
    while pos[0] < len(token) and token[pos[0]].isalpha():
        word.append(token[pos[0]].lower())
        pos[0] += 1
    return True, ''.join(word)

關(guān)鍵設(shè)計點

  • pos參數(shù)用列表傳引用:Python 中整數(shù)是不可變類型,用列表包裹可實現(xiàn) “跨循環(huán)修改位置”(避免用全局變量);
  • 分步處理:先跳過無效字符,再提取有效字母,確保只保留純字母單詞;
  • 統(tǒng)一轉(zhuǎn)小寫:避免 “Apple” 和 “apple” 被識別為不同單詞。

(2)哈希函數(shù)(my_hash)

選擇經(jīng)典的 Time33 算法,兼顧效率與哈希分布均勻性:

def my_hash(word: str) -> int:
    h = 0
    for char in word:
        h = (h << 5) + h + ord(char)  # 等價于h = h*33 + ord(char)(左移5位=乘32,加h=乘33)
    return h % HASH_SIZE  # 映射到哈希表的桶索引

設(shè)計理由

  • Time33 是工業(yè)界常用的輕量哈希算法(如 URL 哈希),實現(xiàn)簡單且沖突率低;
  • 最終取模HASH_SIZE:將哈希值映射到 [0,1008] 的范圍,適配哈希表的桶數(shù)量。

(3)順序查找函數(shù)(linear_search)

實現(xiàn)線性表的順序查找,返回 “是否找到 + 比較次數(shù)”(為 ASL 計算提供數(shù)據(jù)):

def linear_search(linear_list: list, word: str) -> tuple[bool, int]:
    cmp_count = 0
    for item in linear_list:
        cmp_count += 1  # 每比較1次,計數(shù)+1
        if item["word"] == word:
            return True, cmp_count
    return False, cmp_count

核心邏輯:遍歷線性表,逐個比較單詞,統(tǒng)計比較次數(shù)(ASL 的核心計算依據(jù))。

(4)快速排序相關(guān)函數(shù)

為二分查找做準備(二分查找要求線性表有序),實現(xiàn) “按單詞字典序排序”:

def swap_linear_node(linear_list: list, i: int, j: int):
    """交換線性表元素,封裝成函數(shù)便于復用"""
    linear_list[i], linear_list[j] = linear_list[j], linear_list[i]

def partition(linear_list: list, low: int, high: int) -> int:
    """快排分區(qū):以最后一個元素為基準,劃分小于/大于基準的區(qū)域"""
    pivot = linear_list[high]["word"]  # 基準值(單詞字典序)
    i = low - 1  # 小于基準的區(qū)域邊界
    for j in range(low, high):
        if linear_list[j]["word"] < pivot:
            i += 1
            swap_linear_node(linear_list, i, j)
    swap_linear_node(linear_list, i + 1, high)  # 基準值歸位
    return i + 1

def quick_sort(linear_list: list, low: int, high: int):
    """快排主函數(shù):遞歸劃分區(qū)域并排序"""
    if low < high:
        pi = partition(linear_list, low, high)
        quick_sort(linear_list, low, pi - 1)  # 排序左半?yún)^(qū)
        quick_sort(linear_list, pi + 1, high)  # 排序右半?yún)^(qū)

設(shè)計點

  • 排序依據(jù)是word字段的字典序:確保二分查找的有序性;
  • 封裝swap_linear_node:避免重復寫交換邏輯,提升代碼可讀性。

(5)二分查找函數(shù)(binary_search)

基于有序線性表實現(xiàn)二分查找,統(tǒng)計比較次數(shù):

def binary_search(linear_list: list, word: str) -> tuple[bool, int]:
    cmp_count = 0
    low, high = 0, len(linear_list) - 1
    while low <= high:
        cmp_count += 1  # 每輪比較計數(shù)+1
        mid = (low + high) // 2
        mid_word = linear_list[mid]["word"]
        if mid_word == word:
            return True, cmp_count
        elif mid_word > word:
            high = mid - 1  # 目標在左半?yún)^(qū)
        else:
            low = mid + 1   # 目標在右半?yún)^(qū)
    return False, cmp_count

核心邏輯:通過 “折半” 縮小查找范圍,對比順序查找可顯著減少比較次數(shù)(體現(xiàn)算法優(yōu)勢)。

3. GUI 交互層開發(fā)(WordAnalyzerApp 類)

封裝所有界面交互邏輯,分為 “UI 搭建”“事件綁定”“核心業(yè)務(wù)邏輯” 三部分。

(1)初始化與 UI 搭建(init+ _setup_ui)

def __init__(self, root):
    self.root = root
    self.root.title("單詞統(tǒng)計與查找分析工具")
    self.root.geometry("800x600")
    self.strategy_var = tk.StringVar(value="1")  # 默認策略1
    self._setup_ui()

def _setup_ui(self):
    # 主容器(統(tǒng)一內(nèi)邊距,提升美觀度)
    main_frame = ttk.Frame(self.root, padding="20")
    main_frame.pack(fill=tk.BOTH, expand=True)

    # 1. 文本輸入?yún)^(qū):帶實時提示
    input_label = ttk.Label(main_frame, text="請輸入待分析文本(輸入#結(jié)束):")
    input_label.pack(anchor=tk.W)
    self.text_input = tk.Text(main_frame, height=10, wrap=tk.WORD)
    self.text_input.pack(fill=tk.X, pady=(0, 5))
    self.input_tip_label = ttk.Label(main_frame, text="", foreground="#666666")
    self.input_tip_label.pack(anchor=tk.W)
    self.text_input.bind("<<Modified>>", self._on_text_changed)  # 綁定實時監(jiān)控事件
    self.text_input_modified = False  # 防止事件重復觸發(fā)

    # 2. 策略選擇區(qū):單選按鈕組
    strategy_frame = ttk.LabelFrame(main_frame, text="查找策略選擇", padding="10")
    strategy_frame.pack(fill=tk.X, pady=(10, 5))
    ttk.Radiobutton(strategy_frame, text="策略1:順序查找", variable=self.strategy_var, value="1", command=self._on_strategy_toggled).pack(side=tk.LEFT, padx=10)
    ttk.Radiobutton(strategy_frame, text="策略2:快速排序+二分查找", variable=self.strategy_var, value="2", command=self._on_strategy_toggled).pack(side=tk.LEFT, padx=10)
    ttk.Radiobutton(strategy_frame, text="策略3:哈希表查找", variable=self.strategy_var, value="3", command=self._on_strategy_toggled).pack(side=tk.LEFT, padx=10)

    # 3. 分析按鈕
    analyze_btn = ttk.Button(main_frame, text="開始分析", command=self._on_analyze_clicked)
    analyze_btn.pack(pady=(10, 10))

    # 4. 結(jié)果顯示區(qū):禁用手動編輯,僅展示結(jié)果
    result_label = ttk.Label(main_frame, text="分析結(jié)果:")
    result_label.pack(anchor=tk.W)
    self.result_display = tk.Text(main_frame, height=10, wrap=tk.WORD, state=tk.DISABLED)
    self.result_display.pack(fill=tk.BOTH, expand=True)

UI 設(shè)計思路

  • 按 “輸入→選擇→操作→輸出” 的流程布局,符合用戶操作習慣;
  • 文本輸入?yún)^(qū)啟用wrap=tk.WORD:按單詞換行,提升長文本可讀性;
  • 結(jié)果區(qū)設(shè)置為tk.DISABLED:防止用戶誤編輯結(jié)果,僅通過代碼更新。

(2)事件綁定與反饋

① 文本輸入實時監(jiān)控(_on_text_changed)

解決 “用戶輸入過程中無反饋” 的問題,實時提示字符數(shù)和#檢測狀態(tài):

def _on_text_changed(self, event):
    if self.text_input_modified:
        return  # 防止重復觸發(fā)
    self.text_input_modified = True

    # 獲取輸入文本,統(tǒng)計字符數(shù),檢測#
    input_text = self.text_input.get("1.0", tk.END).strip()
    char_count = len(input_text)
    has_sharp = "#" in input_text

    # 生成提示文本,區(qū)分顏色(有#時橙色提示)
    tip = f"實時狀態(tài):已輸入 {char_count} 個字符 | "
    if has_sharp:
        tip += "檢測到#,分析時會截斷#后的內(nèi)容"
        self.input_tip_label.config(foreground="#E67E22")
    else:
        tip += "未檢測到#,將分析全部文本"
        self.input_tip_label.config(foreground="#666666")
    self.input_tip_label.config(text=tip)

    # 重置modified標志,避免循環(huán)觸發(fā)
    self.text_input.edit_modified(False)
    self.text_input_modified = False

關(guān)鍵優(yōu)化

  • self.text_input_modified標志防止<<Modified>>事件重復觸發(fā)(tkinter 的該事件會多次觸發(fā));
  • 顏色區(qū)分提示:橙色提示#截斷規(guī)則,提升用戶感知。

② 策略切換反饋(_on_strategy_toggled)

def _on_strategy_toggled(self):
    strategy_id = self.strategy_var.get()
    strategy_names = {"1": "順序查找", "2": "快速排序+二分查找", "3": "哈希表查找"}
    strategy_name = strategy_names.get(strategy_id, "未知")
    self._update_result(f"已切換為【{strategy_name}】策略,請點擊「開始分析」重新計算結(jié)果", "#3498DB")

設(shè)計點:策略切換后即時清空結(jié)果區(qū)并提示,引導用戶重新分析,避免結(jié)果與策略不匹配。

③ 結(jié)果更新封裝(_update_result)

def _update_result(self, text: str, color: str = "#000000"):
    self.result_display.config(state=tk.NORMAL)  # 臨時啟用編輯
    self.result_display.delete("1.0", tk.END)     # 清空原有內(nèi)容
    self.result_display.insert(tk.END, text)      # 插入新結(jié)果
    self.result_display.config(foreground=color, state=tk.DISABLED)  # 禁用編輯,設(shè)置顏色

封裝理由:結(jié)果更新邏輯復用(策略切換、分析完成都需調(diào)用),減少重復代碼。

(3)核心業(yè)務(wù)邏輯(_on_analyze_clicked)

這是 GUI 與算法層的 “橋梁”,實現(xiàn) “文本解析→策略執(zhí)行→指標計算→結(jié)果展示” 的全流程:

def _on_analyze_clicked(self):
    # 1. 輸入預(yù)處理:獲取文本,截斷#后的內(nèi)容
    input_text = self.text_input.get("1.0", tk.END).strip()
    strategy = int(self.strategy_var.get())
    if "#" in input_text:
        input_text = input_text.split("#")[0]

    # 2. 初始化數(shù)據(jù)結(jié)構(gòu)
    linear_list = []  # 策略1/2用
    hash_table = [[] for _ in range(HASH_SIZE)]  # 策略3用(鏈地址法)
    total_words = 0
    unique_words = 0
    total_cmp = 0

    # 3. 解析并統(tǒng)計單詞(調(diào)用normalize函數(shù))
    pos = [0]
    token = input_text
    while True:
        has_word, word = normalize(token, pos)
        if not has_word:
            break
        total_words += 1

        # 策略1/2:線性表統(tǒng)計
        if strategy in (1, 2):
            found, _ = linear_search(linear_list, word)
            if found:
                for item in linear_list:
                    if item["word"] == word:
                        item["count"] += 1
                        break
            else:
                linear_list.append({"word": word, "count": 1})
        # 策略3:哈希表統(tǒng)計(鏈地址法解決沖突)
        elif strategy == 3:
            h = my_hash(word)
            found = False
            for item in hash_table[h]:
                if item["word"] == word:
                    item["count"] += 1
                    found = True
                    break
            if not found:
                hash_table[h].append({"word": word, "count": 1})

    # 4. 計算Unique Words和ASL(核心指標)
    if strategy == 1:
        # 順序查找:遍歷線性表,累加比較次數(shù)
        unique_words = len(linear_list)
        for item in linear_list:
            _, cmp = linear_search(linear_list, item["word"])
            total_cmp += cmp
        asl = total_cmp / unique_words if unique_words > 0 else 0.0

    elif strategy == 2:
        # 快排+二分:先排序,再二分查找統(tǒng)計比較次數(shù)
        unique_words = len(linear_list)
        if unique_words > 0:
            quick_sort(linear_list, 0, unique_words - 1)
            for item in linear_list:
                _, cmp = binary_search(linear_list, item["word"])
                total_cmp += cmp
        asl = total_cmp / unique_words if unique_words > 0 else 0.0

    elif strategy == 3:
        # 哈希表:統(tǒng)計桶中元素數(shù)(Unique Words),累加鏈表位置作為比較次數(shù)
        unique_words = 0
        for bucket in hash_table:
            unique_words += len(bucket)
        for bucket in hash_table:
            for idx, item in enumerate(bucket):
                total_cmp += (idx + 1)  # 鏈表位置從1開始
        asl = total_cmp / unique_words if unique_words > 0 else 0.0

    # 5. 格式化展示結(jié)果
    result = (
        f"Total Words: {total_words}\n"
        f"Unique Words: {unique_words}\n"
        f"ASL: {asl:.2f}\n\n"
        "測試自動換行:這是一段很長的文本,用于驗證結(jié)果區(qū)的自動換行功能是否生效,當文本長度超過控件寬度時,會自動換行顯示,不需要手動添加換行符。"
    )
    self._update_result(result)

核心設(shè)計點

  • 數(shù)據(jù)結(jié)構(gòu)適配:策略 1/2 復用線性表,策略 3 用 “列表嵌套列表” 模擬哈希表的鏈地址法(解決哈希沖突);
  • ASL 計算邏輯:
    • 順序查找:每個單詞的比較次數(shù) = 其在列表中的位置;
    • 二分查找:基于有序表的折半比較次數(shù);
    • 哈希表:比較次數(shù) = 單詞在哈希桶鏈表中的位置(鏈地址法的查找次數(shù));
  • 邊界處理:unique_words=0時 ASL 設(shè)為 0,避免除以 0 錯誤。

六、第五階段:測試與優(yōu)化

開發(fā)完成后,覆蓋多場景測試并優(yōu)化體驗,確保工具穩(wěn)定可用:

1. 核心測試場景

測試場景測試目的預(yù)期結(jié)果
輸入空文本驗證邊界處理,避免崩潰Total Words=0,Unique Words=0,ASL=0.00
輸入帶 #的文本(如 “Hi#Hello”)驗證 #截斷邏輯僅解析 “Hi”,Total Words=1
輸入含非字母的文本(如 “Hi! 123 Apple”)驗證 normalize 函數(shù)的標準化邏輯僅提取 “hi”“apple”,統(tǒng)一轉(zhuǎn)小寫
三種策略對比(相同文本)驗證算法效率差異策略 1 ASL 最大,策略 3 ASL 最?。üP首罡撸?/td>
超長單詞(50 + 字母)驗證 MAX_WORD_LEN 的限制(代碼中隱含處理)正常提取,無內(nèi)存溢出

2. 關(guān)鍵優(yōu)化點

  • 防止事件重復觸發(fā):通過self.text_input_modified標志解決<<Modified>>事件多次觸發(fā)的問題;
  • 實時反饋優(yōu)化:輸入?yún)^(qū)提示字符數(shù)和 #檢測狀態(tài),策略切換即時提示;
  • 結(jié)果格式化:ASL 保留 2 位小數(shù),結(jié)果區(qū)啟用自動換行,提升可讀性;
  • 異常防護:處理unique_words=0的情況,避免除以 0 錯誤;
  • 代碼解耦:算法函數(shù)與 GUI 完全分離,可單獨測試算法邏輯(如直接調(diào)用linear_search驗證查找次數(shù))。

七、單詞統(tǒng)計與查找分析工具的Python代碼完整實現(xiàn)

import tkinter as tk
from tkinter import ttk, messagebox
import re
import sys

# ===================== 全局常量 =====================
MAX_LINEAR_SIZE = 10000  # 線性表最大容量
HASH_SIZE = 1009  # 哈希表大?。◤娭?009)
MAX_WORD_LEN = 50  # 單詞最大長度


# ===================== 核心算法函數(shù) =====================
def normalize(token: str, pos: list) -> tuple[bool, str]:
    """
    標準化單詞:跳過非字母字符,提取連續(xù)字母并轉(zhuǎn)小寫
    :param token: 待處理字符串
    :param pos: 當前處理位置(用列表傳引用,Python整數(shù)不可變)
    :return: (是否提取到單詞, 標準化后的單詞)
    """
    # 跳過非字母字符
    while pos[0] < len(token) and not token[pos[0]].isalpha():
        pos[0] += 1

    if pos[0] >= len(token):
        return False, ""

    # 提取連續(xù)字母并轉(zhuǎn)小寫
    word = []
    while pos[0] < len(token) and token[pos[0]].isalpha():
        word.append(token[pos[0]].lower())
        pos[0] += 1

    return True, ''.join(word)


def my_hash(word: str) -> int:
    """Time33哈希函數(shù)"""
    h = 0
    for char in word:
        h = (h << 5) + h + ord(char)  # h = h*33 + 字符ASCII
    return h % HASH_SIZE


def linear_search(linear_list: list, word: str) -> tuple[bool, int]:
    """
    順序查找
    :return: (是否找到, 比較次數(shù))
    """
    cmp_count = 0
    for item in linear_list:
        cmp_count += 1
        if item["word"] == word:
            return True, cmp_count
    return False, cmp_count


# 快速排序相關(guān)函數(shù)(按單詞字典序)
def swap_linear_node(linear_list: list, i: int, j: int):
    """交換線性表中的兩個元素"""
    linear_list[i], linear_list[j] = linear_list[j], linear_list[i]


def partition(linear_list: list, low: int, high: int) -> int:
    """快排分區(qū)函數(shù)"""
    pivot = linear_list[high]["word"]
    i = low - 1  # 小于基準的區(qū)域邊界

    for j in range(low, high):
        if linear_list[j]["word"] < pivot:
            i += 1
            swap_linear_node(linear_list, i, j)

    swap_linear_node(linear_list, i + 1, high)
    return i + 1


def quick_sort(linear_list: list, low: int, high: int):
    """快速排序主函數(shù)"""
    if low < high:
        pi = partition(linear_list, low, high)
        quick_sort(linear_list, low, pi - 1)
        quick_sort(linear_list, pi + 1, high)


def binary_search(linear_list: list, word: str) -> tuple[bool, int]:
    """
    二分查找(需先排序)
    :return: (是否找到, 比較次數(shù))
    """
    cmp_count = 0
    low, high = 0, len(linear_list) - 1

    while low <= high:
        cmp_count += 1
        mid = (low + high) // 2
        mid_word = linear_list[mid]["word"]

        if mid_word == word:
            return True, cmp_count
        elif mid_word > word:
            high = mid - 1
        else:
            low = mid + 1

    return False, cmp_count


# ===================== GUI主類 =====================
class WordAnalyzerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("單詞統(tǒng)計與查找分析工具")
        self.root.geometry("800x600")

        # 策略選擇變量
        self.strategy_var = tk.StringVar(value="1")

        # 初始化UI
        self._setup_ui()

    def _setup_ui(self):
        """構(gòu)建GUI界面"""
        # 主容器
        main_frame = ttk.Frame(self.root, padding="20")
        main_frame.pack(fill=tk.BOTH, expand=True)

        # 1. 文本輸入?yún)^(qū)域
        input_label = ttk.Label(main_frame, text="請輸入待分析文本(輸入#結(jié)束):")
        input_label.pack(anchor=tk.W)

        self.text_input = tk.Text(main_frame, height=10, wrap=tk.WORD)
        self.text_input.pack(fill=tk.X, pady=(0, 5))

        # 實時提示標簽
        self.input_tip_label = ttk.Label(main_frame, text="", foreground="#666666")
        self.input_tip_label.pack(anchor=tk.W)

        # 綁定文本實時監(jiān)控事件
        self.text_input.bind("<<Modified>>", self._on_text_changed)
        self.text_input_modified = False  # 防止重復觸發(fā)

        # 2. 策略選擇區(qū)域
        strategy_frame = ttk.LabelFrame(main_frame, text="查找策略選擇", padding="10")
        strategy_frame.pack(fill=tk.X, pady=(10, 5))

        # 策略單選按鈕
        ttk.Radiobutton(
            strategy_frame, text="策略1:順序查找",
            variable=self.strategy_var, value="1",
            command=self._on_strategy_toggled
        ).pack(side=tk.LEFT, padx=10)

        ttk.Radiobutton(
            strategy_frame, text="策略2:快速排序+二分查找",
            variable=self.strategy_var, value="2",
            command=self._on_strategy_toggled
        ).pack(side=tk.LEFT, padx=10)

        ttk.Radiobutton(
            strategy_frame, text="策略3:哈希表查找",
            variable=self.strategy_var, value="3",
            command=self._on_strategy_toggled
        ).pack(side=tk.LEFT, padx=10)

        # 3. 分析按鈕
        analyze_btn = ttk.Button(
            main_frame, text="開始分析",
            command=self._on_analyze_clicked
        )
        analyze_btn.pack(pady=(10, 10))

        # 4. 結(jié)果顯示區(qū)域
        result_label = ttk.Label(main_frame, text="分析結(jié)果:")
        result_label.pack(anchor=tk.W)

        self.result_display = tk.Text(main_frame, height=10, wrap=tk.WORD, state=tk.DISABLED)
        self.result_display.pack(fill=tk.BOTH, expand=True)

    def _on_text_changed(self, event):
        """文本輸入實時監(jiān)控"""
        if self.text_input_modified:
            return
        self.text_input_modified = True

        # 獲取輸入文本
        input_text = self.text_input.get("1.0", tk.END).strip()
        char_count = len(input_text)
        has_sharp = "#" in input_text

        # 更新提示文本
        tip = f"實時狀態(tài):已輸入 {char_count} 個字符 | "
        if has_sharp:
            tip += "檢測到#,分析時會截斷#后的內(nèi)容"
            self.input_tip_label.config(foreground="#E67E22")
        else:
            tip += "未檢測到#,將分析全部文本"
            self.input_tip_label.config(foreground="#666666")
        self.input_tip_label.config(text=tip)

        # 重置modified標志
        self.text_input.edit_modified(False)
        self.text_input_modified = False

    def _on_strategy_toggled(self):
        """策略切換反饋"""
        strategy_id = self.strategy_var.get()
        strategy_names = {
            "1": "順序查找",
            "2": "快速排序+二分查找",
            "3": "哈希表查找"
        }
        strategy_name = strategy_names.get(strategy_id, "未知")

        # 清空結(jié)果區(qū)并提示
        self._update_result(f"已切換為【{strategy_name}】策略,請點擊「開始分析」重新計算結(jié)果", "#3498DB")

    def _update_result(self, text: str, color: str = "#000000"):
        """更新結(jié)果顯示區(qū)"""
        self.result_display.config(state=tk.NORMAL)
        self.result_display.delete("1.0", tk.END)
        self.result_display.insert(tk.END, text)
        self.result_display.config(foreground=color, state=tk.DISABLED)

    def _on_analyze_clicked(self):
        """分析按鈕點擊事件"""
        # 1. 獲取輸入和策略
        input_text = self.text_input.get("1.0", tk.END).strip()
        strategy = int(self.strategy_var.get())

        # 處理#結(jié)束符
        if "#" in input_text:
            input_text = input_text.split("#")[0]

        # 2. 初始化數(shù)據(jù)結(jié)構(gòu)
        linear_list = []  # 策略1/2:存儲{"word": xxx, "count": xxx}
        hash_table = [[] for _ in range(HASH_SIZE)]  # 策略3:哈希表(列表模擬鏈表)
        total_words = 0
        unique_words = 0
        total_cmp = 0

        # 3. 解析并統(tǒng)計單詞
        pos = [0]  # 用列表傳引用
        token = input_text
        while True:
            has_word, word = normalize(token, pos)
            if not has_word:
                break
            total_words += 1

            # 策略1/2:線性表處理
            if strategy in (1, 2):
                found, _ = linear_search(linear_list, word)
                if found:
                    # 單詞已存在,計數(shù)+1
                    for item in linear_list:
                        if item["word"] == word:
                            item["count"] += 1
                            break
                else:
                    # 新增單詞
                    linear_list.append({"word": word, "count": 1})

            # 策略3:哈希表處理
            elif strategy == 3:
                h = my_hash(word)
                found = False
                # 遍歷哈希桶中的單詞
                for item in hash_table[h]:
                    if item["word"] == word:
                        item["count"] += 1
                        found = True
                        break
                if not found:
                    hash_table[h].append({"word": word, "count": 1})

        # 4. 計算Unique Words和ASL
        if strategy == 1:
            # 順序查找策略
            unique_words = len(linear_list)
            for item in linear_list:
                _, cmp = linear_search(linear_list, item["word"])
                total_cmp += cmp
            asl = total_cmp / unique_words if unique_words > 0 else 0.0

        elif strategy == 2:
            # 快排+二分查找策略
            unique_words = len(linear_list)
            if unique_words > 0:
                quick_sort(linear_list, 0, unique_words - 1)
                for item in linear_list:
                    _, cmp = binary_search(linear_list, item["word"])
                    total_cmp += cmp
            asl = total_cmp / unique_words if unique_words > 0 else 0.0

        elif strategy == 3:
            # 哈希表策略
            # 統(tǒng)計唯一單詞數(shù)
            unique_words = 0
            for bucket in hash_table:
                unique_words += len(bucket)
            # 統(tǒng)計總比較次數(shù)
            for bucket in hash_table:
                for idx, item in enumerate(bucket):
                    total_cmp += (idx + 1)  # 鏈表位置從1開始
            asl = total_cmp / unique_words if unique_words > 0 else 0.0

        # 5. 顯示結(jié)果
        result = (
            f"Total Words: {total_words}\n"
            f"Unique Words: {unique_words}\n"
            f"ASL: {asl:.2f}\n\n"
            "測試自動換行:這是一段很長的文本,用于驗證結(jié)果區(qū)的自動換行功能是否生效,當文本長度超過控件寬度時,會自動換行顯示,不需要手動添加換行符。"
        )
        self._update_result(result)


# ===================== 主函數(shù) =====================
if __name__ == "__main__":
    root = tk.Tk()
    app = WordAnalyzerApp(root)
    root.mainloop()

八、程序運行截圖展示

九、打包項目

步驟 1:創(chuàng)建并激活純凈虛擬環(huán)境

打開 Anaconda Prompt,執(zhí)行以下命令(復制粘貼即可):

# 1. 創(chuàng)建僅包含Python 3.10的純凈環(huán)境(兼容性最佳,適配tkinter/matplotlib/pandas)
conda create -n word_analyzer_tool python=3.10 -y

# 2. 激活該環(huán)境
conda activate word_analyzer_tool

# 3. 僅安裝必需依賴(清華源加速,包含matplotlib可視化依賴)
pip install pandas matplotlib openpyxl pyinstaller -i https://pypi.tuna.tsinghua.edu.cn/simple/

步驟 2:切換目錄并快速打包

# 切換到你的單詞統(tǒng)計工具代碼所在文件夾(替換為實際路徑)
cd C:\Users\你的用戶名\PycharmProjects\WordAnalyzerTool

# 用目錄模式打包(-D),速度快、體積小、穩(wěn)定性高;-w隱藏控制臺(GUI工具必備);--collect-data 確保matplotlib資源被打包
pyinstaller -w -n 單詞統(tǒng)計與查找分析工具 -D --collect-data matplotlib 單詞統(tǒng)計與查找分析工具.py

額外參數(shù)說明:--collect-data matplotlib 是為了確保 matplotlib 的字體、配置等資源被正確打包,避免可視化功能運行報錯。

步驟 3:驗證結(jié)果

  • 打包時間:僅需 2-3 分鐘(因包含 matplotlib,略長于基礎(chǔ)工具);
  • exe 位置dist\單詞統(tǒng)計與查找分析工具\ 目錄下的 單詞統(tǒng)計與查找分析工具.exe;
  • 體積:約 120-180MB(因包含 matplotlib 依賴,對比全局環(huán)境打包的 2GB+,大幅精簡);
  • 功能驗證:雙擊 exe,測試文本導入 / 輸入、策略切換、ASL 可視化、單詞統(tǒng)計等核心功能,和原代碼完全一致。

十、單詞統(tǒng)計與查找分析工具(增強版)

(一)可擴展方向

  • 增加 “單詞頻次排行榜”:展示出現(xiàn)次數(shù)最多的前 N 個單詞;
  • 支持文件導入:解析文本文件(.txt),而非僅手動輸入;
  • 算法對比可視化:用柱狀圖展示三種策略的 ASL 差異;
  • 自定義哈希表大?。涸试S用戶調(diào)整 HASH_SIZE,觀察沖突率變化;
  • 增加單詞長度統(tǒng)計:分析文本中單詞的平均長度、最長單詞等指標。

(二)單詞統(tǒng)計與查找分析工具擴展后的Python代碼完整實現(xiàn)

import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import re
import sys
import matplotlib

# 設(shè)置matplotlib后端為TkAgg,適配tkinter
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

# ===================== 全局常量(基礎(chǔ)默認值) =====================
MAX_LINEAR_SIZE = 10000  # 線性表最大容量
DEFAULT_HASH_SIZE = 1009  # 默認哈希表大小
MAX_WORD_LEN = 50  # 單詞最大長度
DEFAULT_RANKING_N = 10  # 默認排行榜展示前10個單詞


# ===================== 核心算法函數(shù)(兼容自定義哈希表大小+性能優(yōu)化) =====================
def normalize(token: str, pos: list) -> tuple[bool, str]:
    """
    標準化單詞:跳過非字母字符,提取連續(xù)字母并轉(zhuǎn)小寫(性能優(yōu)化版)
    :param token: 待處理字符串
    :param pos: 當前處理位置(用列表傳引用,Python整數(shù)不可變)
    :return: (是否提取到單詞, 標準化后的單詞)
    """
    start = pos[0]
    # 跳過非字母字符(優(yōu)化循環(huán)邏輯)
    while start < len(token) and not token[start].isalpha():
        start += 1

    if start >= len(token):
        pos[0] = start
        return False, ""

    # 提取連續(xù)字母(一次性切片,減少循環(huán)次數(shù))
    end = start
    while end < len(token) and token[end].isalpha():
        end += 1

    pos[0] = end
    return True, token[start:end].lower()


def my_hash(word: str, hash_size: int) -> int:
    """Time33哈希函數(shù)(適配自定義哈希表大?。?""
    h = 0
    for char in word:
        h = (h << 5) + h + ord(char)  # h = h*33 + 字符ASCII
    return h % hash_size


def linear_search(linear_list: list, word: str) -> tuple[bool, int]:
    """
    順序查找
    :return: (是否找到, 比較次數(shù))
    """
    cmp_count = 0
    for item in linear_list:
        cmp_count += 1
        if item["word"] == word:
            return True, cmp_count
    return False, cmp_count


# 快速排序相關(guān)函數(shù)(按單詞字典序)
def swap_linear_node(linear_list: list, i: int, j: int):
    """交換線性表中的兩個元素"""
    linear_list[i], linear_list[j] = linear_list[j], linear_list[i]


def partition(linear_list: list, low: int, high: int) -> int:
    """快排分區(qū)函數(shù)"""
    pivot = linear_list[high]["word"]
    i = low - 1  # 小于基準的區(qū)域邊界

    for j in range(low, high):
        if linear_list[j]["word"] < pivot:
            i += 1
            swap_linear_node(linear_list, i, j)

    swap_linear_node(linear_list, i + 1, high)
    return i + 1


def quick_sort(linear_list: list, low: int, high: int):
    """快速排序主函數(shù)"""
    if low < high:
        pi = partition(linear_list, low, high)
        quick_sort(linear_list, low, pi - 1)
        quick_sort(linear_list, pi + 1, high)


def binary_search(linear_list: list, word: str) -> tuple[bool, int]:
    """
    二分查找(需先排序)
    :return: (是否找到, 比較次數(shù))
    """
    cmp_count = 0
    low, high = 0, len(linear_list) - 1

    while low <= high:
        cmp_count += 1
        mid = (low + high) // 2
        mid_word = linear_list[mid]["word"]

        if mid_word == word:
            return True, cmp_count
        elif mid_word > word:
            high = mid - 1
        else:
            low = mid + 1

    return False, cmp_count


# ===================== 新增工具函數(shù) =====================
def calculate_word_length_stats(word_list: list) -> dict:
    """計算單詞長度統(tǒng)計指標"""
    if not word_list:
        return {
            "avg_length": 0.0,
            "max_len_word": "",
            "max_length": 0,
            "min_len_word": "",
            "min_length": 0
        }

    lengths = [len(word["word"]) for word in word_list]
    avg_length = sum(lengths) / len(lengths)
    max_idx = lengths.index(max(lengths))
    min_idx = lengths.index(min(lengths))

    return {
        "avg_length": round(avg_length, 2),
        "max_len_word": word_list[max_idx]["word"],
        "max_length": max(lengths),
        "min_len_word": word_list[min_idx]["word"],
        "min_length": min(lengths)
    }


def get_word_ranking(word_list: list, top_n: int) -> list:
    """生成單詞頻次排行榜(降序)"""
    if not word_list:
        return []
    # 按頻次降序排序,頻次相同按單詞字典序升序
    sorted_list = sorted(word_list, key=lambda x: (-x["count"], x["word"]))
    # 處理top_n超過列表長度的情況
    top_n = min(top_n, len(sorted_list))
    return sorted_list[:top_n]


def analyze_all_strategies(input_text: str, hash_size: int) -> dict:
    """批量分析三種策略的ASL,用于可視化"""
    # 第一步:解析文本得到所有單詞
    pos = [0]
    token = input_text
    all_words = []
    while True:
        has_word, word = normalize(token, pos)
        if not has_word:
            break
        all_words.append(word)

    if not all_words:
        return {"strategy1_asl": 0, "strategy2_asl": 0, "strategy3_asl": 0}

    # 策略1:順序查找
    linear_list1 = []
    for word in all_words:
        found, _ = linear_search(linear_list1, word)
        if found:
            for item in linear_list1:
                if item["word"] == word:
                    item["count"] += 1
                    break
        else:
            linear_list1.append({"word": word, "count": 1})
    unique1 = len(linear_list1)
    total_cmp1 = sum([linear_search(linear_list1, item["word"])[1] for item in linear_list1])
    strategy1_asl = total_cmp1 / unique1 if unique1 > 0 else 0

    # 策略2:快排+二分
    linear_list2 = linear_list1.copy()
    quick_sort(linear_list2, 0, len(linear_list2) - 1)
    total_cmp2 = sum([binary_search(linear_list2, item["word"])[1] for item in linear_list2])
    strategy2_asl = total_cmp2 / unique1 if unique1 > 0 else 0

    # 策略3:哈希表
    hash_table = [[] for _ in range(hash_size)]
    for word in all_words:
        h = my_hash(word, hash_size)
        found = False
        for item in hash_table[h]:
            if item["word"] == word:
                item["count"] += 1
                found = True
                break
        if not found:
            hash_table[h].append({"word": word, "count": 1})
    unique3 = sum([len(bucket) for bucket in hash_table])
    total_cmp3 = sum([idx + 1 for bucket in hash_table for idx, item in enumerate(bucket)])
    strategy3_asl = total_cmp3 / unique3 if unique3 > 0 else 0

    return {
        "strategy1_asl": round(strategy1_asl, 2),
        "strategy2_asl": round(strategy2_asl, 2),
        "strategy3_asl": round(strategy3_asl, 2)
    }


# ===================== GUI主類(集成所有新增功能) =====================
class WordAnalyzerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("單詞統(tǒng)計與查找分析工具(增強版)")
        self.root.geometry("1000x800")  # 擴大窗口適配新功能

        # 添加窗口關(guān)閉事件處理(優(yōu)雅退出)
        self.root.protocol("WM_DELETE_WINDOW", self._on_window_close)

        # 核心變量
        self.strategy_var = tk.StringVar(value="1")
        self.hash_size_var = tk.StringVar(value=str(DEFAULT_HASH_SIZE))
        self.ranking_n_var = tk.StringVar(value=str(DEFAULT_RANKING_N))
        self.all_strategies_asl = {"strategy1_asl": 0, "strategy2_asl": 0, "strategy3_asl": 0}

        # 初始化UI
        self._setup_ui()

    def _setup_ui(self):
        """構(gòu)建GUI界面(新增功能組件)"""
        # 主容器
        main_frame = ttk.Frame(self.root, padding="20")
        main_frame.pack(fill=tk.BOTH, expand=True)

        # 1. 文件導入 + 文本輸入?yún)^(qū)域
        file_frame = ttk.Frame(main_frame)
        file_frame.pack(fill=tk.X, pady=(0, 5))

        # 導入文件按鈕
        import_btn = ttk.Button(file_frame, text="導入文本文件(.txt)", command=self._import_file)
        import_btn.pack(side=tk.LEFT, padx=(0, 10))

        # 哈希表大小設(shè)置
        hash_label = ttk.Label(file_frame, text="哈希表大?。?)
        hash_label.pack(side=tk.LEFT, padx=(10, 5))
        hash_entry = ttk.Entry(file_frame, textvariable=self.hash_size_var, width=10)
        hash_entry.pack(side=tk.LEFT, padx=(0, 10))
        ttk.Label(file_frame, text="(建議輸入質(zhì)數(shù))").pack(side=tk.LEFT)

        # 文本輸入?yún)^(qū)域
        input_label = ttk.Label(main_frame, text="請輸入待分析文本(輸入#結(jié)束):")
        input_label.pack(anchor=tk.W)
        self.text_input = tk.Text(main_frame, height=8, wrap=tk.WORD)
        self.text_input.pack(fill=tk.X, pady=(0, 5))

        # 實時提示標簽
        self.input_tip_label = ttk.Label(main_frame, text="", foreground="#666666")
        self.input_tip_label.pack(anchor=tk.W)
        self.text_input.bind("<<Modified>>", self._on_text_changed)
        self.text_input_modified = False

        # 2. 策略選擇 + 排行榜設(shè)置區(qū)域
        setting_frame = ttk.LabelFrame(main_frame, text="分析設(shè)置", padding="10")
        setting_frame.pack(fill=tk.X, pady=(10, 5))

        # 策略單選按鈕
        strategy_subframe = ttk.Frame(setting_frame)
        strategy_subframe.pack(side=tk.LEFT, padx=10)
        ttk.Radiobutton(
            strategy_subframe, text="策略1:順序查找",
            variable=self.strategy_var, value="1",
            command=self._on_strategy_toggled
        ).pack(side=tk.LEFT, padx=5)
        ttk.Radiobutton(
            strategy_subframe, text="策略2:快速排序+二分查找",
            variable=self.strategy_var, value="2",
            command=self._on_strategy_toggled
        ).pack(side=tk.LEFT, padx=5)
        ttk.Radiobutton(
            strategy_subframe, text="策略3:哈希表查找",
            variable=self.strategy_var, value="3",
            command=self._on_strategy_toggled
        ).pack(side=tk.LEFT, padx=5)

        # 排行榜設(shè)置
        ranking_subframe = ttk.Frame(setting_frame)
        ranking_subframe.pack(side=tk.RIGHT, padx=10)
        ttk.Label(ranking_subframe, text="頻次排行榜前N個單詞:").pack(side=tk.LEFT, padx=5)
        ranking_entry = ttk.Entry(ranking_subframe, textvariable=self.ranking_n_var, width=5)
        ranking_entry.pack(side=tk.LEFT, padx=5)

        # 3. 功能按鈕區(qū)域
        btn_frame = ttk.Frame(main_frame)
        btn_frame.pack(fill=tk.X, pady=(10, 10))

        # 開始分析按鈕
        analyze_btn = ttk.Button(btn_frame, text="開始分析", command=self._on_analyze_clicked)
        analyze_btn.pack(side=tk.LEFT, padx=(0, 10))

        # ASL可視化按鈕
        asl_chart_btn = ttk.Button(btn_frame, text="ASL算法對比可視化", command=self._show_asl_chart)
        asl_chart_btn.pack(side=tk.LEFT)

        # 4. 結(jié)果顯示區(qū)域
        result_label = ttk.Label(main_frame, text="分析結(jié)果:")
        result_label.pack(anchor=tk.W)
        self.result_display = tk.Text(main_frame, height=12, wrap=tk.WORD, state=tk.DISABLED)
        self.result_display.pack(fill=tk.BOTH, expand=True)

    def _import_file(self):
        """導入txt文本文件"""
        file_path = filedialog.askopenfilename(
            title="選擇文本文件",
            filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
        )
        if not file_path:
            return

        try:
            with open(file_path, "r", encoding="utf-8") as f:
                content = f.read()
            # 清空原有內(nèi)容,插入文件內(nèi)容
            self.text_input.delete("1.0", tk.END)
            self.text_input.insert(tk.END, content)
            messagebox.showinfo("成功", f"已導入文件:{file_path}")
        except Exception as e:
            messagebox.showerror("錯誤", f"文件導入失?。簕str(e)}")

    def _on_text_changed(self, event):
        """文本輸入實時監(jiān)控"""
        if self.text_input_modified:
            return
        self.text_input_modified = True

        input_text = self.text_input.get("1.0", tk.END).strip()
        char_count = len(input_text)
        has_sharp = "#" in input_text

        tip = f"實時狀態(tài):已輸入 {char_count} 個字符 | "
        if has_sharp:
            tip += "檢測到#,分析時會截斷#后的內(nèi)容"
            self.input_tip_label.config(foreground="#E67E22")
        else:
            tip += "未檢測到#,將分析全部文本"
            self.input_tip_label.config(foreground="#666666")
        self.input_tip_label.config(text=tip)

        self.text_input.edit_modified(False)
        self.text_input_modified = False

    def _on_strategy_toggled(self):
        """策略切換反饋"""
        strategy_id = self.strategy_var.get()
        strategy_names = {
            "1": "順序查找",
            "2": "快速排序+二分查找",
            "3": "哈希表查找"
        }
        strategy_name = strategy_names.get(strategy_id, "未知")
        self._update_result(f"已切換為【{strategy_name}】策略,請點擊「開始分析」重新計算結(jié)果", "#3498DB")

    def _update_result(self, text: str, color: str = "#000000"):
        """更新結(jié)果顯示區(qū)"""
        self.result_display.config(state=tk.NORMAL)
        self.result_display.delete("1.0", tk.END)
        self.result_display.insert(tk.END, text)
        self.result_display.config(foreground=color, state=tk.DISABLED)

    def _show_asl_chart(self):
        """繪制ASL算法對比柱狀圖"""
        input_text = self.text_input.get("1.0", tk.END).strip()
        if "#" in input_text:
            input_text = input_text.split("#")[0]
        if not input_text.strip():
            messagebox.showwarning("提示", "請先輸入/導入文本內(nèi)容!")
            return

        # 驗證哈希表大小輸入
        try:
            hash_size = int(self.hash_size_var.get())
            if hash_size <= 0:
                raise ValueError
        except ValueError:
            messagebox.showerror("錯誤", "哈希表大小必須為正整數(shù)!")
            return

        # 批量分析三種策略的ASL
        self.all_strategies_asl = analyze_all_strategies(input_text, hash_size)

        # 創(chuàng)建圖表窗口
        chart_window = tk.Toplevel(self.root)
        chart_window.title("ASL算法對比柱狀圖")
        chart_window.geometry("600x400")

        # 關(guān)鍵修改:字體設(shè)置移到創(chuàng)建圖表之前,確保生效
        plt.rcParams["font.family"] = ["SimHei", "Microsoft YaHei", "WenQuanYi Micro Hei"]
        plt.rcParams["axes.unicode_minus"] = False  # 解決負號顯示問題

        # 繪制柱狀圖
        fig, ax = plt.subplots(figsize=(8, 5))

        strategies = ["順序查找", "快排+二分查找", "哈希表查找"]
        asl_values = [
            self.all_strategies_asl["strategy1_asl"],
            self.all_strategies_asl["strategy2_asl"],
            self.all_strategies_asl["strategy3_asl"]
        ]

        ax.bar(strategies, asl_values, color=['#FF6B6B', '#4ECDC4', '#45B7D1'])

        # 優(yōu)化y軸刻度(解決數(shù)據(jù)差異過大導致小值被壓縮的問題)
        ax.set_yscale("log")  # 改用對數(shù)刻度,適配ASL的數(shù)量級差異
        ax.set_xlabel("查找策略")
        ax.set_ylabel("平均查找長度(ASL,對數(shù)刻度)")
        ax.set_title("不同查找策略的ASL對比")
        ax.grid(axis='y', linestyle='--', alpha=0.7)

        # 調(diào)整數(shù)值標簽位置(適配對數(shù)刻度)
        for i, v in enumerate(asl_values):
            # 數(shù)值標簽顯示在柱子頂部,避免重疊
            ax.text(i, v * 1.1, f"{v:.2f}", ha='center', va='bottom', fontsize=10)

        # 將圖表嵌入tkinter窗口
        canvas = FigureCanvasTkAgg(fig, master=chart_window)
        canvas.draw()
        canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)

    def _on_analyze_clicked(self):
        """分析按鈕點擊事件(集成所有新增統(tǒng)計)"""
        # 1. 輸入驗證與預(yù)處理
        input_text = self.text_input.get("1.0", tk.END).strip()
        strategy = int(self.strategy_var.get())
        if "#" in input_text:
            input_text = input_text.split("#")[0]
        if not input_text.strip():
            self._update_result("請輸入/導入待分析的文本內(nèi)容!", "#E74C3C")
            return

        # 驗證哈希表大小輸入
        try:
            hash_size = int(self.hash_size_var.get())
            if hash_size <= 0:
                raise ValueError
        except ValueError:
            messagebox.showerror("錯誤", "哈希表大小必須為正整數(shù)!")
            return

        # 驗證排行榜N值輸入
        try:
            ranking_n = int(self.ranking_n_var.get())
            if ranking_n <= 0:
                raise ValueError
        except ValueError:
            messagebox.showerror("錯誤", "排行榜N值必須為正整數(shù)!")
            return

        # 2. 初始化數(shù)據(jù)結(jié)構(gòu)
        linear_list = []
        hash_table = [[] for _ in range(hash_size)]
        total_words = 0
        unique_words = 0
        total_cmp = 0
        word_length_records = []  # 存儲所有單詞(用于長度統(tǒng)計)

        # 3. 解析并統(tǒng)計單詞
        pos = [0]
        token = input_text
        while True:
            has_word, word = normalize(token, pos)
            if not has_word:
                break
            total_words += 1

            # 策略1/2:線性表處理
            if strategy in (1, 2):
                found, _ = linear_search(linear_list, word)
                if found:
                    for item in linear_list:
                        if item["word"] == word:
                            item["count"] += 1
                            break
                else:
                    linear_list.append({"word": word, "count": 1})
                word_length_records = linear_list  # 同步到長度統(tǒng)計列表

            # 策略3:哈希表處理
            elif strategy == 3:
                h = my_hash(word, hash_size)
                found = False
                for item in hash_table[h]:
                    if item["word"] == word:
                        item["count"] += 1
                        found = True
                        break
                if not found:
                    hash_table[h].append({"word": word, "count": 1})
                # 整理哈希表數(shù)據(jù)用于長度統(tǒng)計
                word_length_records = []
                for bucket in hash_table:
                    word_length_records.extend(bucket)

        # 4. 計算核心指標
        asl = 0.0
        if strategy == 1:
            unique_words = len(linear_list)
            total_cmp = sum([linear_search(linear_list, item["word"])[1] for item in linear_list])
            asl = total_cmp / unique_words if unique_words > 0 else 0.0

        elif strategy == 2:
            unique_words = len(linear_list)
            if unique_words > 0:
                quick_sort(linear_list, 0, unique_words - 1)
                total_cmp = sum([binary_search(linear_list, item["word"])[1] for item in linear_list])
            asl = total_cmp / unique_words if unique_words > 0 else 0.0

        elif strategy == 3:
            unique_words = sum([len(bucket) for bucket in hash_table])
            total_cmp = sum([idx + 1 for bucket in hash_table for idx, item in enumerate(bucket)])
            asl = total_cmp / unique_words if unique_words > 0 else 0.0

        # 5. 計算新增統(tǒng)計指標
        length_stats = calculate_word_length_stats(word_length_records)
        ranking_list = get_word_ranking(word_length_records, ranking_n)

        # 6. 格式化結(jié)果展示
        result = f"===== 基礎(chǔ)統(tǒng)計 =====\n"
        result += f"Total Words(總單詞數(shù)): {total_words}\n"
        result += f"Unique Words(唯一單詞數(shù)): {unique_words}\n"
        result += f"ASL(平均查找長度): {asl:.2f}\n\n"

        result += f"===== 單詞長度統(tǒng)計 =====\n"
        result += f"平均單詞長度: {length_stats['avg_length']}\n"
        result += f"最長單詞: {length_stats['max_len_word']}(長度:{length_stats['max_length']})\n"
        result += f"最短單詞: {length_stats['min_len_word']}(長度:{length_stats['min_length']})\n\n"

        result += f"===== 單詞頻次排行榜(前{ranking_n}個)=====\n"
        if ranking_list:
            for idx, item in enumerate(ranking_list, 1):
                result += f"{idx}. {item['word']} - 出現(xiàn)次數(shù):{item['count']}\n"
        else:
            result += "暫無單詞數(shù)據(jù)\n"

        self._update_result(result)

    def _on_window_close(self):
        """優(yōu)雅關(guān)閉窗口,避免強制退出導致的中斷報錯"""
        self.root.quit()
        self.root.destroy()


# ===================== 主函數(shù)(捕獲中斷+優(yōu)雅退出) =====================
if __name__ == "__main__":
    try:
        root = tk.Tk()
        app = WordAnalyzerApp(root)
        root.mainloop()
    except KeyboardInterrupt:
        print("程序已被用戶手動終止,正在優(yōu)雅退出...")
        root.quit()
        root.destroy()
    except Exception as e:
        print(f"程序運行出錯:{str(e)}")
        sys.exit(1)

(三)核心新增功能說明

1. 自定義哈希表大小

  • 在 UI 中新增哈希表大小輸入框,默認值為 1009,支持用戶自定義;
  • 增加輸入驗證(必須為正整數(shù)),避免無效輸入;
  • 核心哈希函數(shù)my_hash新增hash_size參數(shù),適配自定義大小。

2. 文件導入功能

  • 新增 “導入文本文件 (.txt)” 按鈕,支持選擇本地 txt 文件;
  • 處理文件讀取異常(編碼、文件不存在等),給出友好提示;
  • 導入后自動將文件內(nèi)容填充到文本輸入框。

3. 單詞長度統(tǒng)計

  • 新增calculate_word_length_stats函數(shù),計算:
    • 平均單詞長度;
    • 最長單詞(及長度);
    • 最短單詞(及長度);
  • 分析結(jié)果中單獨展示長度統(tǒng)計模塊,數(shù)據(jù)格式化輸出。

4. 單詞頻次排行榜

  • 新增排行榜 N 值輸入框(默認前 10),支持自定義展示數(shù)量;
  • 新增get_word_ranking函數(shù),按頻次降序排序(頻次相同按單詞字典序);
  • 處理 N 值超過唯一單詞數(shù)的邊界情況,避免報錯。

5. ASL 算法對比可視化

  • 集成 matplotlib,適配 tkinter 后端;
  • 新增analyze_all_strategies函數(shù),批量計算三種策略的 ASL;
  • 點擊 “ASL 算法對比可視化” 按鈕,彈出獨立窗口展示柱狀圖,直觀對比三種策略的 ASL 差異;
  • 柱狀圖添加數(shù)值標簽、網(wǎng)格線,提升可讀性。

(四)使用注意事項

  1. 運行前需安裝 matplotlib:pip install matplotlib;
  2. 哈希表大小建議輸入質(zhì)數(shù)(如 1009、997 等),可減少哈希沖突;
  3. 可視化功能需先執(zhí)行文本分析,確保有有效數(shù)據(jù);
  4. 支持的文本文件編碼為 UTF-8,若導入其他編碼文件(如 GBK),可手動修改_import_file函數(shù)中的編碼參數(shù)。

(五)程序運行截圖展示

(六)打包項目

根據(jù)本文的打包項目的方法,擴展版和原始版的代碼必須在同一目錄下,可以直接運行下面命令:

pyinstaller -w -n 單詞統(tǒng)計與查找分析工具(增強版) -D --collect-data matplotlib 單詞統(tǒng)計與查找分析工具擴展版.py

十一、總結(jié)

本文介紹了一款單詞統(tǒng)計與查找分析工具的設(shè)計與實現(xiàn)。該工具支持三種查找策略(順序查找、快速排序+二分查找、哈希表查找),可計算文本中的單詞總數(shù)、唯一單詞數(shù)和平均查找長度(ASL)。工具采用Python開發(fā),包含核心算法層和GUI交互層,具有文本標準化處理、實時狀態(tài)提示和多策略對比功能。擴展版新增了文件導入、單詞長度統(tǒng)計、頻次排行榜和ASL可視化等功能,支持自定義哈希表大小。文章詳細闡述了工具的技術(shù)選型、架構(gòu)設(shè)計、核心算法實現(xiàn)和測試優(yōu)化過程,并提供了完整的Python代碼實現(xiàn)和打包方法。

以上就是基于Python實現(xiàn)的單詞統(tǒng)計與查找分析工具的詳細內(nèi)容,更多關(guān)于Python單詞統(tǒng)計與查找工具的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 學習和使用python的13個理由

    學習和使用python的13個理由

    在本篇文章里小編給大家整理了關(guān)于學習和使用python的13個理由以及相關(guān)知識點,需要的朋友們參考下。
    2019-07-07
  • Python實現(xiàn)Word文檔的圖片插入與排版技巧

    Python實現(xiàn)Word文檔的圖片插入與排版技巧

    在創(chuàng)建專業(yè)文檔時,圖片是傳達信息、增強視覺效果的重要元素,本文將詳細介紹如何使用 Python 在 Word 文檔中插入圖片并進行各種高級處理,感興趣的小伙伴可以了解下
    2026-03-03
  • Django--權(quán)限Permissions的例子

    Django--權(quán)限Permissions的例子

    今天小編就為大家分享一篇Django--權(quán)限Permissions的例子,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-08-08
  • pytest解讀一次請求多個fixtures及多次請求

    pytest解讀一次請求多個fixtures及多次請求

    這篇文章主要為大家介紹了一次請求多個fixtures,以及fixtures被多次請求的pytest官方解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • Playwright的wait funtion測試的實現(xiàn)

    Playwright的wait funtion測試的實現(xiàn)

    本文主要介紹了Playwright的wait funtion測試的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2026-04-04
  • Python圖像處理二值化方法實例匯總

    Python圖像處理二值化方法實例匯總

    這篇文章主要介紹了Python圖像處理二值化方法實例匯總,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-07-07
  • python 執(zhí)行函數(shù)的九種方法

    python 執(zhí)行函數(shù)的九種方法

    這篇文章主要介紹了python 執(zhí)行函數(shù)的九種方法,幫助大家更好的理解和學習使用python,感興趣的朋友可以了解下
    2021-03-03
  • Python偽隨機數(shù)模塊random詳解

    Python偽隨機數(shù)模塊random詳解

    這篇文章主要為大家詳細介紹了Python偽隨機數(shù)模塊random,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • django-celery-beat搭建定時任務(wù)的實現(xiàn)

    django-celery-beat搭建定時任務(wù)的實現(xiàn)

    本文主要介紹了django-celery-beat搭建定時任務(wù)的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-03-03
  • python 使用while寫猜年齡小游戲過程解析

    python 使用while寫猜年齡小游戲過程解析

    這篇文章主要介紹了python 使用while寫猜年齡小游戲過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-10-10

最新評論

昌都县| 尚义县| 嘉荫县| 勃利县| 青州市| 淳化县| 沁阳市| 卫辉市| 托克逊县| 大竹县| 九台市| 白水县| 洮南市| 临安市| 遂昌县| 孟连| 鄂托克前旗| 信丰县| 时尚| 万山特区| 邵阳县| 文安县| 金沙县| 茶陵县| 宁德市| 朔州市| 利辛县| 桑植县| 博客| 永吉县| 苏州市| 涪陵区| 二连浩特市| 清丰县| 巴南区| 宜兰县| 胶州市| 阳原县| 四子王旗| 鄄城县| 浙江省|