这是我在技术面试中遇到的一个问题。目录中有500,000个文件,这些文件的配置使它们始终按字母顺序排列。他们有这样的名字:
...
您希望重命名所有文件,同时保留其订单:
...
你可能会在这里看到明显的问题。如果将Afile重命名为File00000001,它将与具有相同名称的现有文件发生冲突,并且订单也会被更改,这不是我们想要的。
这里的问题是,如何设计具有最佳运行时间的算法来有效地执行重命名任务?
答案 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位数字。