首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

C# 遞歸與非遞歸遍歷目錄的三種實現對比

     編輯:Java 相關知識

前言:為什麼要避免遞歸?

遞歸雖然代碼簡潔,但存在顯著缺陷:調用棧深度不可控,易導致 StackOverflowError;調用鏈未結束時,棧幀內的變量與引用無法釋放,造成內存壓力與 CPU 開銷。對於深度未知的目錄樹,改用顯式棧(深度優先)或隊列(廣度優先)的迭代寫法,能徹底規避上述風險。

三種遍歷實現對比

1. 遞歸版(基準實現)

private static void RecursiveTraverse(string path, ref List<string> files) {
    // 獲取文件
    string[] fileEntries = Directory.GetFiles(path);
    if (fileEntries.Length > 0) files.AddRange(fileEntries);

    // 遞歸子目錄
    string[] subDirs = Directory.GetDirectories(path);
    foreach (var dir in subDirs) RecursiveTraverse(dir, ref files);
}

缺點:深度過大時棧溢出;異常處理分散。

2. 顯式棧版(深度優先,DFS)

private static void StackTraverse(string root, ref List<string> files) {
    var stack = new Stack<string>();
    stack.Push(root);

    while (stack.Count > 0) {
        string dir = stack.Pop();
        // 處理文件
        files.AddRange(Directory.GetFiles(dir));
        // 子目錄入棧(逆序入棧可保持原序)
        foreach (var sub in Directory.GetDirectories(dir).Reverse())
            stack.Push(sub);
    }
}

優點:可控內存,無棧溢出風險;易於加入中斷/進度回調。

3. 隊列版(廣度優先,BFS)

private static void QueueTraverse(string root, ref List<string> files) {
    var queue = new Queue<string>();
    queue.Enqueue(root);

    while (queue.Count > 0) {
        string dir = queue.Dequeue();
        files.AddRange(Directory.GetFiles(dir));
        foreach (var sub in Directory.GetDirectories(dir))
            queue.Enqueue(sub);
    }
}

優點:層級順序輸出,適合需按目錄深度處理的場景。

關鍵細節:if (true) { ... } 的作用

代碼中出現的 if (true) { ... } 看似多餘,實則是為了限制變量作用域(如 files、folders),讓編譯器更早回收記憶體,並在某些編譯器優化下生成更緊湊的 IL 代碼。

性能與適用場景總結

方式內存佔用順序適用場景
遞歸不可控(棧幀)DFS淺層、確定深度
顯式棧可控(堆上)DFS深層、需回溯邏輯
隊列可控(堆上)BFS分層處理、最短路徑

實戰建議:默認優先選擇顯式棧(DFS),兼顧性能與代碼簡潔;僅在需要層級遍歷時改用隊列。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved