最顶层合并文件夹列表

时间:2015-02-20 18:22:00

标签: c++ algorithm boost

我正在寻找一种算法,它将获取一个文件夹列表并返回一个"至少"的列表。顶级文件夹。

换句话说,我的意见是:

/abc/sub
/abc
/xxx/yyy/zzz
/xxx/yyy/zzz/iii/foobar
/www/zzz
/www/zzz/ppp
/www/xxx

输出应为

/abc
/xxx/yyy/zzz
/www/zzz
/www/xxx

我可以自由使用Boost库,如果有一种简单的方法可以测试文件夹是否是层次结构中任意位置较高的另一个文件夹的子文件夹,这可能会有所帮助,但我找不到类似的东西。那。

我在实验中不断回归的解决方案呈指数级复杂。我想知道是否有我失踪的东西以及是否有更好的方式。

谢谢!

2 个答案:

答案 0 :(得分:1)

您构建trie,每个节点都是路径组件。因此,当您看到第一条路径/abc/sub时,您的trie有两个节点:

abc
  - sub

当您看到/abc时,检查trie并看到它已作为顶级节点存在,但您添加一个空引用作为子节点以指示您将路径名称视为输入,没有任何跟随它。然后你得到下一个,/xxx/yyy/zzz,你的结构变成了:

abc
  - <empty>
  - sub
      - <empty>
xxx
  - yyy
      - zzz
          - <empty>

当你完成后,你的完整特里是:

abc
  - empty
  - sub
      - <empty>
xxx
  - yyy
      - zzz
          - <empty>
          - iii
              - foobar
                  - <empty>
www
  - zzz
      - <empty>
      - ppp
  - xxx
      - <empty>

<empty>条目表示您已经看到在该节点处终止的引用。也就是说,您看到了/xxx/yyy/zzz,但您从未见过/xxx/yyy

现在,您可以遍历trie来生成输出,使用您定义的任何规则来表示“最低”顶级。我想你的意思是你想要没有分支的最高级节点。

答案 1 :(得分:1)

我认为这非常简洁:

void bottom(std::vector<std::string>& input)
{
    std::vector<std::string>::iterator curr = input.begin();

    std::vector<std::string>::iterator next = curr + 1;

    std::string::iterator last = curr->begin();

    // Sort lexicographically
    std::sort(input.begin(), input.end());

    while (next < input.end())
    {
        // Find next folder ending in current path
        last = std::find(++last, curr->end(), '/');

        // Temporary boolean
        bool equal = std::equal(curr->begin(), last, next->begin());

        // If the path so far is final, all other paths that go as far as or further
        // than this path fold into this path and can be deleted
        // If the current path is different from the next, we just increment to the
        // next path string because the current one must be a final level
        if (last == curr->end() || ! equal)
        {
            // The boolean is stored so that this check here isn't duplicated, but
            // the same if clause can be used for both possibilities stated above
            while (equal && next != input.end())
            {
                next = input.erase(next);

                // New next
                equal = std::equal(curr->begin(), last, next->begin());
            }

            curr = next++;

            last = curr->begin();
        }
    }
}