我正在使用正常的递归方法来迭代并从java中的文件夹和子文件夹中获取文件。
有人可以帮助我改变尾部递归方法吗?我无法理解尾递归是什么。这对我来说很有用。
public void findFiles(String filePath) throws IOException {
List<File> files = Files.list(Paths.get(filePath))
.map(path -> path.toFile())
.collect(Collectors.toList());
for(File file: files) {
if(file.isDirectory()){
if(file.list().length == 0){
boolean isDeleted = file.delete();
}else{
findFiles(file.getAbsolutePath());
}
}else{
//process files
}
}
}
这是我的正常递归,有人可以帮我写这个尾递归吗?
我尝试了一种方法,但我不确定这是否是尾递归及其工作原理。
public static void findFiles(String filePath) throws IOException{
List<File> files = Files.list(Paths.get(filePath))
.map(path -> path.toFile())
.collect(Collectors.toList());
for(File file: files) {
if(file.isDirectory() && file.list().length == 0){
boolean isDeleted = file.delete();
}else if(!file.isDirectory()){
System.out.println("Processing files!!!" + file.getAbsolutePath());
}
if(file.isDirectory()) {
findFiles(file.getAbsolutePath());
}
}
}
提前致谢。
尾递归是一种特殊的递归,它在递归调用之后不做任何事情但返回。
一些编程语言通过优化调用堆栈来利用这一点,因此如果你有一个非常深的递归,你不会最终出现堆栈溢出(除了内存和调用效率增益本身)。
经常使用的技巧是添加一个额外的累加器参数,该参数可以处理任何未完成的数据。由于这可能使递归函数不太可用,因此它通常是单独完成的,因此对于函数的用户来说它看起来很简单。
所以在你的例子中它就像这样,正常的findFiles()
只是准备递归调用,而private
findFilesRecursive()
正在进行尾递归工作。
public void findFiles(String filePath) throws IOException {
//we use a Deque<> for Last In First Out ordering (to keep subfolders with their parent)
Deque<Path> paths = new ArrayDeque<Path>();
paths.add(Paths.get(filePath);
return findFilesRecursive(paths);
}
private void findFilesRecursive(Deque<Path> pending) {
if (pending.isEmpty()) {
//base case, we are ready
return;
}
Path path = pending.removeFirst();
if (Files.isRegularFile(path)) {
//todo: process the file
} else {
//it is a directory, queue its subfolders for processing
List<Path> inside = Files.list(path).collect(Collectors.toList());
if (inside.isEmpty() {
Files.delete(path);
} else {
//we use LIFO so that subfolders get processed first
inside.forEach(pending::addFirst);
}
}
//tail recursion, we do nothing after we call it
return findFilesRecursive(pending);
}
请注意,Java不会(yet)利用尾递归。其他编程语言,如Scala和Kotlin。
旁注,Path
通常比旧的File
更强大,你不需要在你的情况下将Path
改为File
。