首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

改進版目錄樹遞迴演算法:突破層級限制

     編輯:關於VC++

問題背景

原版《遍歷資料夾並建成目錄樹》使用固定層級變數 (`strHTFir`~`strHtFif`),導致目錄深度超過 5 層時無法正確顯示。本文提供通用遞迴解法,移除層級限制。

原版缺陷分析


// 原版:硬編碼層級變數,switch-case 判斷深度
switch(CallNum) {
    case 1: item = tree.InsertItem(title, 0, 0, NULL); break;
    case 2: item = tree.InsertItem(title, 0, 0, strHTFir); break;
    case 3: item = tree.InsertItem(title, 0, 0, strHTSec); break;
    // ... 最多支援 5 層
    default: item = tree.InsertItem(title, 0, 0, strHtFif); break;
}

缺點:維護困難、深度固定、程式碼重複、擴充性差。

改進版:通用遞迴函式


void CFileTreeDlg::BrowseDir(CString strDir, HTREEITEM hParent)
{
    CFileFind finder;
    CString searchPath = strDir;
    
    // 確保路徑結尾有反斜線
    if (searchPath.Right(1) != _T("\\")) searchPath += _T("\\");
    searchPath += _T("*.*");
    
    BOOL bFound = finder.FindFile(searchPath);
    while (bFound) {
        bFound = finder.FindNextFile();
        
        // 跳過 . 和 ..
        if (finder.IsDots()) continue;
        
        CString strTitle = finder.GetFileName();
        HTREEITEM hItem = m_FileTree.InsertItem(strTitle, 0, 0, hParent);
        
        if (finder.IsDirectory()) {
            // 遞迴處理子目錄,傳入當前項目作為父節點
            BrowseDir(finder.GetFilePath(), hItem);
        }
        // 檔案節點無需遞迴,直接插入即可
    }
    finder.Close();
}

呼叫方式


BOOL CFileTreeDlg::OnInitDialog()
{
    CDialog::OnInitDialog();
    // ... 圖示列表初始化 ...
    
    // 根節點傳入 NULL,自動建立樹狀結構
    BrowseDir(_T("成績表"), NULL);
    return TRUE;
}

關鍵改進點對比

特性原版改進版
最大深度5 層 (硬編碼)無限制 (受限於堆疊/記憶體)
程式碼行數~120 行~30 行
維護性差 (重複 switch-case)優 (單一遞迴邏輯)
效能相同相同
記憶體用量固定變數遞迴堆疊框架

進階優化建議

  • 非遞迴實作:使用 `std::stack` 或 `CArray` 模擬堆疊,避免深層目錄導致堆疊溢位
  • 非同步載入:大型目錄樹採用虛擬模式 (`TVS_EX_AUTOHSCROLL`),展開時才載入子節點
  • 圖示快取:使用 `SHGetFileInfo` 取得系統圖示並快取,避免重複提取
  • 錯誤處理:加入 `CFileFind::FindFile` 失敗時的權限錯誤處理

非遞迴版本範例


struct DirNode { CString path; HTREEITEM hParent; };
std::stack dirStack;
dirStack.push({_T("成績表"), NULL});

while (!dirStack.empty()) {
    DirNode node = dirStack.top(); dirStack.pop();
    CFileFind finder;
    CString search = node.path;
    if (search.Right(1) != _T("\\")) search += _T("\\");
    search += _T("*.*");
    
    BOOL found = finder.FindFile(search);
    while (found) {
        found = finder.FindNextFile();
        if (finder.IsDots()) continue;
        
        HTREEITEM hItem = m_FileTree.InsertItem(finder.GetFileName(), 0, 0, node.hParent);
        if (finder.IsDirectory()) {
            dirStack.push({finder.GetFilePath(), hItem});
        }
    }
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved