首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

Java 遞歸計算目錄大小:全局變量 vs 局部變量導致結果指數級膨脹

     編輯:程式設計疑難解答

問題代碼對比

❌ 錯誤寫法:全局變量 + 返回值雙重累加


public class Directory {
    static long size = 0; // 全局變量
    
    public static long getSize(File file) {
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {
                size += getSize(f); // 💥 雙重累加:全局變量累加 + 返回值又累加
            }
        } else {
            size += file.length(); // 全局變量累加
        }
        return size; // 返回累加後的全局值
    }
}

✅ 正確寫法:局部變量累加返回


public class Directory {
    public static long getSize(File file) {
        long size = 0; // 局部變量,每次調用獨立
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            if (files != null) {
                for (File f : files) {
                    size += getSize(f); // 只累加返回值
                }
            }
        } else {
            size += file.length();
        }
        return size; // 返回當前文件/目錄大小
    }
}

錯誤機制圖解:指數級膨脹


目錄結構:
root/
├── a.txt (100B)
└── sub/
    └── b.txt (200B)

正確邏輯 (局部變量):
getSize(root):
  size=0
  getSize(a.txt) → 返回 100 → size=100
  getSize(sub):
    size=0
    getSize(b.txt) → 返回 200 → size=200
    返回 200
  size += 200 → size=300
  返回 300 ✓

錯誤邏輯 (全局變量 size):
初始 size=0
getSize(root):
  getSize(a.txt): size=100, return 100
  size += 100 → size=200  (第一次膨脹)
  getSize(sub):
    getSize(b.txt): size=400, return 400
    size += 400 → size=800  (第二次膨脹)
    return 800
  size += 800 → size=1600 (第三次膨脹)
  return 1600 ✗ (真實 300B 變 1600B)

核心原理

維度全局變量局部變量
生命周期整個程序運行期間單次方法調用期間
遞歸共享所有遞歸層級共享**同一個**變量每層遞歸擁有**獨立**變量
返回值語義返回「截至目前的總和」返回「當前節點的大小」
累加邏輯全局累加 + 返回值再累加 = 雙重計算僅通過返回值層層匯總

修正後完整代碼


import java.io.File;
import java.util.Scanner;

public class Directory {
    public static void main(String[] args) {
        System.out.print("請輸入目錄路徑: ");
        Scanner scanner = new Scanner(System.in);
        String path = scanner.nextLine();
        File dir = new File(path);
        
        if (!dir.exists() || !dir.isDirectory()) {
            System.out.println("路徑無效或不是目錄");
            return;
        }
        
        long size = getSize(dir);
        System.out.printf("目錄大小: %,d bytes (%.2f MB)%n", size, size / 1024.0 / 1024.0);
    }
    
    public static long getSize(File file) {
        long size = 0;
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            if (files != null) {
                for (File f : files) {
                    size += getSize(f);
                }
            }
        } else {
            size += file.length();
        }
        return size;
    }
}

進階優化:Files.walk (Java 8+)


public static long getSizeModern(Path path) throws IOException {
    return Files.walk(path)
        .filter(Files::isRegularFile)
        .mapToLong(p -> p.toFile().length())
        .sum();
}

總結

  • 🚫 **遞歸中禁用全局/成員變量累加結果**
  • ✅ **每層遞歸用局部變量接收子調用返回值並匯總**
  • 💡 **口訣**:遞歸返回「自己管轄的大小」,父層負責「加起來」
  • 🔍 **調試技巧**:在遞歸入口/出口打印 size 觀察變化
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved