使用尾部递归检索文件夹和子文件夹以读取java中的文件
我使用普通的递归方法来迭代并从java中的文件夹和子文件夹中获取文件 有人能帮我把它改成尾部递归方法吗?我不明白什么是尾部递归。了解这一点对我很有帮助使用尾部递归检索文件夹和子文件夹以读取java中的文件,java,recursion,java-8,filesystems,tail-recursion,Java,Recursion,Java 8,Filesystems,Tail Recursion,我使用普通的递归方法来迭代并从java中的文件夹和子文件夹中获取文件 有人能帮我把它改成尾部递归方法吗?我不明白什么是尾部递归。了解这一点对我很有帮助 public void findFiles(String filePath) throws IOException { List<File> files = Files.list(Paths.get(filePath)) .map(path -> path.toFi
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 void findFiles(字符串文件路径)引发IOException{
List files=files.List(path.get(filePath))
.map(路径->路径.toFile())
.collect(Collectors.toList());
用于(文件:文件){
如果(file.isDirectory()){
if(file.list().length==0){
布尔值isDeleted=file.delete();
}否则{
FindFile(file.getAbsolutePath());
}
}否则{
//处理文件
}
}
}
这是我的正常递归,有人能帮我写一个尾部递归吗
我尝试了一种方法,但我不确定这是否是尾部递归以及它是如何工作的
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());
}
}
}
publicstaticvoidfindfiles(stringfilepath)抛出IOException{
List files=files.List(path.get(filePath))
.map(路径->路径.toFile())
.collect(Collectors.toList());
用于(文件:文件){
if(file.isDirectory()&&file.list().length==0){
布尔值isDeleted=file.delete();
}else如果(!file.isDirectory()){
System.out.println(“处理文件!!!”+file.getAbsolutePath());
}
if(file.isDirectory()){
FindFile(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);
}
public void findFiles(字符串文件路径)引发IOException{
//我们使用Deque进行后进先出排序(将子文件夹与其父文件夹保持在一起)
Deque路径=新的ArrayDeque();
path.add(path.get)(filePath);
返回findFilesRecursive(路径);
}
私有void findFilesRecursive(Deque待定){
if(pending.isEmpty()){
//基本情况下,我们准备好了
返回;
}
Path Path=pending.removeFirst();
if(Files.isRegularFile(path)){
//todo:处理该文件
}否则{
//它是一个目录,将其子文件夹排入队列进行处理
List inside=Files.List(path.collect(Collectors.toList());
if(inside.isEmpty()中){
删除(路径);
}否则{
//我们使用后进先出(LIFO),以便首先处理子文件夹
inside.forEach(挂起::addFirst);
}
}
//尾部递归,我们调用它之后什么也不做
返回findFileRecursive(待定);
}
请注意,Java()没有利用尾部递归,其他编程语言如Scala和Kotlin也有
旁注,
路径
通常比旧的文件
更强大,在您的情况下,您不需要将路径
更改为文件
。当递归调用是函数执行的最后一件事时,递归函数是尾部递归的。@CommonMan-我在谷歌上搜索过,每个人都这么说。在我的情况下,阅读目录和子目录中的文件,否则是调用我的函数的正确位置吗?这就是我感到困惑的地方。用我厌倦的内容更新了帖子。你能帮我吗?如果findFiles(file.getAbsolutePath())
出现在循环的最后,然后是尾部递归,但我看到您在循环中使用了另外两个,所以它还不是尾部递归不一定是最后一件事,它在一个循环中,因此在它返回后可能还有其他工作要做。我必须检查文件上次修改的时间并删除该文件。因此,在这种情况下,我必须更改文件的路径,对吗?不是真的。只需执行Files.getLastModifiedTime(path)
和Files.delete(path)
。太好了!!谢谢你的帮助。但是因为Java没有利用尾部递归,所以用这种方式重写它是没有意义的,除非我们也重写它来使用循环而不是递归,递归现在很简单。顺便说一句,我会使用ArrayDeque
,它消耗的内存要少得多。@jbx不要混淆ArrayDeque
使用ArrayList
。一个具体的区别是ArrayQue
可以从前面和从后面一样快地删除(否则,以Deque
的形式提供它是毫无意义的)。调整大小不涉及深度复制,只需复制一个引用数组,即使有可能调整大小,它也可以“固定摊销时间成本”用于添加一个元素(两端)和净性能,在大多数情况下仍优于LinkedList
。