首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >访问:使用数据结构重命名目录中的所有文件

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

Stack Overflow用户
提问于 2018-03-10 06:25:41
回答 2查看 54关注 0票数 1

这是我在科技面试中遇到的一个问题。您在一个目录中有500万个文件,该目录被配置为始终按字母顺序排列。他们有这样的名字:

  • 阿非尔
  • Bfile
  • File00000001
  • File00000002

..。

您希望重命名所有文件,同时保留它们的order如下:

  • File00000001
  • File00000002
  • File00000003

..。

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

这里的问题是,如何设计一个具有最优运行时间的算法来高效地完成重命名任务?

EN

回答 2

Stack Overflow用户

发布于 2018-03-10 10:09:20

您不能按升序和不按递减顺序遍历文件,这两者都可能导致冲突。另外,首先将文件重命名为其他文件可能会导致冲突。目标似乎是只重命名每个文件一次,因此您可以这样做:

代码语言:javascript
运行
复制
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,但两者都不是,所以没有循环重命名。如果有太多的文件,那么递归深度可能是不够的,我们必须用堆栈来实现它,但这是相同的原则。

代码语言:javascript
运行
复制
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
EN

Stack Overflow用户

发布于 2018-03-10 11:20:56

代码语言:javascript
运行
复制
for i in {100..1..-1} ; do o=$(printf "File%04d" $i); n=$(printf "File%04d" $((i + 2))); echo mv $o $n; done; 

或更易读的:

代码语言:javascript
运行
复制
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语法;注意到这一点很重要。它还没有mv文件,只是回覆mv-命令。

不要试图并行运行它。:)

但是你也可以将它们按相反的,正常的顺序移动到一个新的dir,然后将它们全部移回旧的dir,以防止压倒一切。这将允许并行执行。

for-语句等效于其他已知的语句。

代码语言:javascript
运行
复制
for (i = 100; i >=1; --i)

代码语言:javascript
运行
复制
printf "File%04d" $i

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49206053

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档