从删除空目录算法中消除递归
本文关键字:递归 算法 删除 | 更新日期: 2023-09-27 18:26:33
我想我以前知道如何做到这一点,但似乎我已经忘记了。
我有一个递归算法来删除目录树中的所有空目录:
static bool DeleteDirectoriesRecursive(string path)
{
var remove = true;
foreach (var dir in System.IO.Directory.GetDirectories(path))
{
remove &= DeleteDirectoriesRecursive(dir);
}
if (remove &= (System.IO.Directory.GetFiles(path).Length == 0))
System.IO.Directory.Delete(path);
return remove;
}
我试图从这个算法中消除递归,而不是"修复"算法(即,类似的问题不使用remove
变量,但我想保留它)。
我已经使用Stack<>
类启动了一个新函数,但我想不出一个好的方法来返回基本路径并执行子目录确定的操作。我想解开无尾递归需要付出更多的努力。
由于Gabe在使用递归时提到了StackOverflowException的可能性,我受到启发,在没有它的情况下完成了这项工作。我将这里的代码作为起点。以下是我的想法。。。
public static bool DeleteDirectories(string root)
{
bool removed = false;
var dirs = new Stack<string>();
var emptyDirStack = new Stack<string>();
var emptyDirs = new Dictionary<string, int>();
if (!System.IO.Directory.Exists(root))
{
throw new ArgumentException();
}
dirs.Push(root);
while (dirs.Count > 0)
{
string currentDir = dirs.Pop();
string[] subDirs;
try
{
subDirs = System.IO.Directory.GetDirectories(currentDir);
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine(e.Message);
continue;
}
catch (System.IO.DirectoryNotFoundException e)
{
Console.WriteLine(e.Message);
continue;
}
if (Directory.GetFiles(currentDir).Length == 0)
{
emptyDirStack.Push(currentDir);
emptyDirs.Add(currentDir, subDirs.Length); // add directory path and number of sub directories
}
// Push the subdirectories onto the stack for traversal.
foreach (string str in subDirs)
dirs.Push(str);
}
while (emptyDirStack.Count > 0)
{
string currentDir = emptyDirStack.Pop();
if (emptyDirs[currentDir] == 0)
{
string parentDir = Directory.GetParent(currentDir).FullName;
Console.WriteLine(currentDir); // comment this line
//Directory.Delete(currentDir); // uncomment this line to delete
if (emptyDirs.ContainsKey(parentDir))
{
emptyDirs[parentDir]--; // decrement number of subdirectories of parent
}
removed = true;
}
}
return removed;
}
几个注意事项:
- 在没有递归的情况下爬行一棵树并不太困难,我在上面链接的MSDN文章中已经完成了这项工作。但这个特殊的例子比他们的要复杂一点
- 我将在
emptyDirs
字典中存储每个不包含文件的目录,以及它包含的子目录数 - 由于删除目录的顺序至关重要,我不得不以相反的顺序运行
emptyDirs
字典(我使用Linq来完成这一操作)
我想还有更有效的方法,但这还不错,而且在我的测试中似乎有效。
更新:我去掉了颠倒的字典,改用第二本。不过,我仍然使用字典进行快速查找。
sans递归版本要困难得多,效率也不高,所以我建议保留递归。此外,这里有一个稍微干净一点的版本:
static bool DeleteDirectoriesRecursive(DirectoryInfo d)
{
bool remove = true;
foreach (DirectoryInfo c in d.GetDirectories())
{
remove &= DeleteDirectoriesRecursive(c);
}
if (remove && d.GetFiles().Length == 0) {
d.Delete();
return true;
}
return false;
}