采访:使用数据结构重命名目录中的所有文件

时间:2018-03-10 06:25:41

标签: algorithm data-structures runtime file-rename

这是我在技术面试中遇到的一个问题。目录中有500,000个文件,这些文件的配置使它们始终按字母顺序排列。他们有这样的名字:

  • å文件
  • BFILE
  • File00000001
  • File00000002

...

您希望重命名所有文件,同时保留其订单

  • File00000001
  • File00000002
  • File00000003

...

你可能会在这里看到明显的问题。如果将Afile重命名为File00000001,它将与具有相同名称的现有文件发生冲突,并且订单也会被更改,这不是我们想要的。

这里的问题是,如何设计具有最佳运行时间的算法来有效地执行重命名任务?

2 个答案:

答案 0 :(得分:1)

您无法按升序浏览文件,也不能按降序排列,两者都可能导致冲突。首先将文件重命名为其他内容可能会导致冲突。目标似乎只是重命名每个文件一次,因此您可以执行以下操作:

private static File dir;

public static void renameFiles(String path) {
    dir = new File(path);
    File[] files = dir.listFiles();
    Map<String, String> map = new HashMap<>();
    int number = 1;
    for (int i = 0; i < files.length; i++)
        if (files[i].isFile())
            map.put(files[i].getName(), "File" + pad(number++));
    // so we created a map with original file names and the name it should get
    for (int i = 0; i < files.length; i++)
        if (!files[i].getName().equals(map.get(files[i].getName())) // not same name
            renameFile(files[i].getName(), map);
}

private static void renameFile(String file, Map<String, String> map) {
    String newName = map.get(file);
    if (newName != null) {
        if (map.containsKey(newName))
            renameFile(newName, map)
        File f = new File(dir, file);
        f.renameTo(new File(dir, newName));
        map.remove(file);
    }
}

时间复杂度O(n)。我们递归继续,直到我们不再有重命名冲突,然后开始从尾部重命名。不会发生冲突,因为File004可能变为File007或File007变为File004但不能同时变为File004,因此不能进行循环重命名。如果文件太多,那么递归深度可能不够,我们必须用堆栈实现它,但它的原理是相同的。

private static void renameFile(String file, Map<String, String> map) {
    String newName = map.get(file);
    if (newName != null) {
        Stack<String> stack = new Stack<>();
        do {
            stack.push(file);
            file = newName;
            newName = map.get(file);
        } while (newName != null);
        while (!stack.empty()) {
            file = stack.pop();
            File f = new File(dir, file);
            f.renameTo(new File(dir, map.get(file)));
            map.remove(file);
        }
    }
}

这适用于Linux,但对于Windows,您仍然可能遇到问题,因为文件名不区分大小写。您可以将地图中的所有键存储为小写,并在访问地图时始终调用toLowerCase()。

答案 1 :(得分:0)

for i in {100..1..-1} ; do o=$(printf "File%04d" $i); n=$(printf "File%04d" $((i + 2))); echo mv $o $n; done; 

或更好的可读性:

for i in {100..1..-1}
do 
   o=$(printf "File%04d" $i)
   n=$(printf "File%04d" $((i + 2)))
   echo mv $o $n
done

可以手动重命名FileA和FileB。

你必须调整大小,但是对于测试,人类数量的文件似乎更适合我。

啊,是的,这就是bash-syntax;重要的是要注意。它还没有mv文件,只能回复mv-command。

请勿尝试并行运行它。 :)

但你也可以将它们以相反的正常顺序移动到新的目录,然后将它们全部移回旧目录,以防止覆盖。这将允许并行执行它。

for语句等同于其他所谓的

for (i = 100; i >=1; --i)

printf "File%04d" $i

打印带有前导零的4位数字。