2012-03-07 12 views
3

非再帰ウォークスルーファイルシステムを使用し、特定の深さにあるファイルをプリントするアプリケーションを作成する必要があります。 私が持っているもの:Java非再帰的ファイルシステムウォーク

public void putFileToQueue() throws IOException, InterruptedException { 
File root = new File(rootPath).getAbsoluteFile(); 
checkFile(root, depth); 
    Queue<DepthControl> queue = new ArrayDeque<DepthControl>(); 
    DepthControl e = new DepthControl(0, root); 
    do { 
     root = e.getFileName(); 

     if (root.isDirectory()) { 
      File[] files = root.listFiles(); 

      if (files != null) 
       for (File file : files) { 

        if (e.getDepth() + 1 <= depth && file.isDirectory()) { 
         queue.offer(new DepthControl(e.getDepth() + 1,file)); 
        } 

        if (file.getName().contains(mask)) { 
         if (e.getDepth() == depth) { 
          System.out.println(Thread.currentThread().getName() 
            + " putting in queue: " 
            + file.getAbsolutePath()); 
         } 
        } 
       } 
       } 
     e = queue.poll(); 
    } while (e != null); 
} 

とヘルパークラス

public class DepthControl { 

    private int depth; 
    private File file; 

    public DepthControl(int depth, File file) { 

     this.depth = depth; 
     this.file = file; 
    } 

    public File getFileName() { 
     return file; 
    } 

    public int getDepth() { 
     return depth; 
    } 
} 

私はこのプログラムが原因幅優先探索(右の翻訳を願っています)の追加メモリを使用していること、答えを受けました。私はO(k^n)を持ちます。ここで、k - サブディレクトリの平均量、n - 深さ。このプログラムはO(k * n)で簡単に実行できます。私のアルゴリズムを修正するのを助けてください。

+2

なぜ非再帰的である必要がありますか? –

+1

@HotLicks、それはおそらく宿題関連の要件です。 – Moonbeam

+1

ちょうど合併症のために、私は思う。面接の仕事です。 – user1255246

答えて

4

私はこれが仕事をしなければならないと思うし、少しシンプルです。次のレベルのファイルを追跡し、展開してプロセスを繰り返します。アルゴリズムそのものは深さを追跡しているので、その余分なクラスは必要ありません。

// start in home directory. 
File root = new File(System.getProperty("user.dir")); 

List<File> expand = new LinkedList<File>(); 
expand.add(root); 

for (int depth = 0; depth < 10; depth++) { 
    File[] expandCopy = expand.toArray(new File[expand.size()]); 
    expand.clear(); 
    for (File file : expandCopy) { 
     System.out.println(depth + " " + file); 
     if (file.isDirectory()) { 
      expand.addAll(Arrays.asList(file.listFiles())); 
     } 
    } 
} 
+0

かなり素敵で美しい。私はこれを試してみる。 – user1255246

+1

しかし、すべての反復をコピーするのでパフォーマンスはひどいですが、まだ美しいコードです。 – user1255246

+0

私は通常、特定のパフォーマンス要件を除いて、パフォーマンスよりも美しさを重視しています。この場合、制限要因はファイルシステムになります。 – Adam

1

二つのオプション基本的にあるツリーを歩いているとき、再帰を避けるために:

  1. 行うべき作業を追跡する(上記と同様)「作業リスト」を使用しますが。結果として「発見」された新しい作業項目は、作業リストに追加されます(FIFO、LIFO、またはランダムな順序が可能です。概念的には問題ありませんが、しばしば「参照の局所性」に影響します)。パフォーマンス)。
  2. スタック/ "プッシュダウンリスト"を使用するので、本質的に再帰スキームをシミュレートします。

#2の場合は、ステートマシンのようなアルゴリズムを作成し、各ステップの後にスタックに戻り、次に何をするかを決定する必要があります。ツリーウォークのスタックエントリには、基本的に、現在のツリーノードと、調べる次の子の子リストへのインデックスが含まれています。あなたが使用するスペースの量を制限したいと仮定すると

+0

#2について読むためのリンクを教えてもらえますか? – user1255246

+0

私は考えましたが、まだそれはより速く動作する方法を得ることができません – user1255246

+0

3つのスキーム(再帰的と上記の2つ)は、それぞれが正確に一度各ノードを訪問するので、同じ "ビッグ-O"効率を持っている必要があります。スキーム#1は、より多くのストレージを使用します - O(n)(n =ノードの総数)は平均ですが、再帰とスキーム#2はO(log n)になると思います。 (私は詳細を効率化するために座っていません。) –

0

  • あなたは、ファイル/ディレクトリのリストを取ることができるが、あなたのトラバーサルの過程にわたって静的で、
  • あなたはのリストを取ることができます所与のディレクトリ内のファイル/ディレクトリは常に

次にあなたが使用してディレクトリを横断できる

  • では、現在のディレクトリの親へのアクセス権を持っているのと同じ順序で返されます最後に訪問したノードの情報。具体的には、

    1. Keep track of the last Entry (directory or file) visited 
    2. Keep track of the current directory 
    3. Get a list of files in the current directory 
    4. Find the index of the last Entry visited in the list of files 
    5. If lastVisited is the last Entry in the current directory, 
    5.1.1 If current directory == start directory, we're done 
    5.1.2 Otherwise, lastVisited = the current directory and current directory is the parent directory 
    5.2. Otherwise, visit the element after lastVisited and set lastVisited to that element 
    6. Repeat from step 3 
    

    の線に沿って何か私ができるなら、私は明日何を意味するか示すためにいくつかのコードを記述しようとするでしょう...しかし、私はちょうど今の時間を持っていません。

    :これは、単に可能な方法...ディレクトリ構造をトラバースするための良い方法ではありません。通常の箱の外、そしておそらく正当な理由があります。

    Javaでサンプルコードを書いてくれないことを許してください。私はatmで作業する時間がありません。 Tclでそれをやることは私にとってはより速く、理解するのは難しいことではありません。だから、言われていること:

    proc getFiles {dir} { 
        set result {} 
        foreach entry [glob -tails -directory $dir * .*] { 
         if { $entry != "." && $entry != ".." } { 
          lappend result [file join $dir $entry] 
         } 
        } 
        return [lsort $result] 
    } 
    
    proc listdir {startDir} { 
        if {! ([file exists $startDir] && [file isdirectory $startDir])} { 
         error "File '$startDir' either doesn't exist or isnt a directory" 
        } 
        set result {} 
        set startDir [file normalize $startDir] 
        set currDir $startDir 
        set currFile {} 
    
        set fileList [getFiles $currDir] 
        for {set i 0} {$i < 1000} {incr i} { # use for to avoid infinate loop 
         set index [expr {1 + ({} == $currFile ? -1 : [lsearch $fileList $currFile])}] 
         if {$index < ([llength $fileList])} { 
          set currFile [lindex $fileList $index] 
          lappend result $currFile 
          if { [file isdirectory $currFile] } { 
           set currDir $currFile 
           set fileList [getFiles $currDir] 
           set currFile {} 
          } 
         } else { 
          # at last entry in the dir, move up one dir 
          if {$currDir == $startDir} { 
           # at the starting directory, we're done 
           return $result 
          } 
          set currFile $currDir 
          set currDir [file dirname $currDir] 
          set fileList [getFiles $currDir] 
         } 
        } 
    } 
    
    puts "Files:\n\t[join [listdir [lindex $argv 0]] \n\t]" 
    

    そして、それを実行している:

    VirtualBox:~/Programming/temp$ ./dirlist.tcl /usr/share/gnome-media/icons/hicolor 
    Files: 
        /usr/share/gnome-media/icons/hicolor/16x16 
        /usr/share/gnome-media/icons/hicolor/16x16/status 
        /usr/share/gnome-media/icons/hicolor/16x16/status/audio-input-microphone-high.png 
        /usr/share/gnome-media/icons/hicolor/16x16/status/audio-input-microphone-low.png 
        /usr/share/gnome-media/icons/hicolor/16x16/status/audio-input-microphone-medium.png 
        /usr/share/gnome-media/icons/hicolor/16x16/status/audio-input-microphone-muted.png 
        /usr/share/gnome-media/icons/hicolor/22x22 
        [snip] 
        /usr/share/gnome-media/icons/hicolor/48x48/devices/audio-subwoofer-testing.svg 
        /usr/share/gnome-media/icons/hicolor/48x48/devices/audio-subwoofer.svg 
        /usr/share/gnome-media/icons/hicolor/scalable 
        /usr/share/gnome-media/icons/hicolor/scalable/status 
        /usr/share/gnome-media/icons/hicolor/scalable/status/audio-input-microphone-high.svg 
        /usr/share/gnome-media/icons/hicolor/scalable/status/audio-input-microphone-low.svg 
        /usr/share/gnome-media/icons/hicolor/scalable/status/audio-input-microphone-medium.svg 
        /usr/share/gnome-media/icons/hicolor/scalable/status/audio-input-microphone-muted.svg 
    
  • +0

    そして、コレクションをスタックに変更するのはどうですか?それはうまくいくように見えますが、この場合のメモリについては何ですか? – user1255246

    +0

    もしそれが正しいとすれば、何らかの永続的な検索状態になります。それは私が最初から考えていたものですが、これをどうやって行うのか分かりませんでした。私は今試してみる。時間がある場合は、実現をポストしてください。または、詳細について読むためのリンクを提供してください。ありがとうございました! – user1255246

    0

    をあなたは、Java 7を使用している場合は、ファイルツリーを歩くのは非常にエレガントな方法があります。あなたはそれがあなたのニーズ再帰を賢明に満たすかどうかを確認する必要があります。

    import java.nio.file.*; 
    import java.nio.file.attribute.BasicFileAttributes; 
    import static java.nio.file.FileVisitResult.*; 
    
    public class myFinder extends SimpleFileVisitor<Path> { 
    
    public FileVisitResult visitFile(Path file, BasicFileAttributes attr) { } 
    public FileVisitResult postVisitDirectory(Path dir, IOException exc) { } 
    public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { } 
    public FileVisitResult visitFileFailed(Path file, IOException exc) { } 
    
    
    <snip> 
    
    } 
    

    基本的には、ツリーの深さ最初の散歩をして、それが/終了するディレクトリを入力し、ときに「訪問」ファイルときに、特定のメソッドを呼び出します。

    これはJava 7に固有のものだと思います。もちろん - -

    http://docs.oracle.com/javase/tutorial/essential/io/walk.html

    +0

    実際のアプリケーションでは非常に便利だと思いますが、私の場合はそうではありません。再帰を使用します。 :(まだ、ポストに感謝しています。javaの新機能を見るには非常に便利です。 – user1255246

    0

    と再帰を回避するために、マルチスレッド化オプションが常にあります。

    1. ファイルのキューを作成します。
    2. ファイルの場合は、キューに追加します。
    3. フォルダの場合は、このキューにフィードするファイルを一覧表示する新しいスレッドを開始します。
    4. 次のアイテムを入手してください。
    5. 必要に応じて2を繰り返します。

    明らかに、これは予測可能な順序でファイルをリストすることはできません。

    関連する問題