如何排序文件夹树

时间:2014-05-25 09:18:28

标签: javascript arrays algorithm sorting

我有一个文件夹的平面树。此树具有以下属性:id,parent_id,name。

这个树我存储在一个简单的数组中。问题是这个数组没有排序。

我的数组的一个元素就是这样的简单对象:

var obj = { id: 1, parent_id: null, name: "Folder" }

我想以这样的方式对它进行排序,以便能够看到这样的事情:

Folder1
  Sub_folder1
    Sub_sub_folder1
  Sub_folder2
    Sub_sub_folder2

所以......我不想使用递归而且我不知道如何正确地做到这一点。

以下是我的一些尝试。我试着添加一个人工字段,它代表集合中每个文件夹的数量,但它确实起作用。

var sort = function(list) {

  var f_map = {};
  var sorting_index = 1;
  var tree = angular.copy(list);

  for(var i = 0; i < tree.length; i++) {

    var node = tree[i];
    f_map[ node.id ]= { index: i, children: [] };

    if (node.parent_id) {
      f_map[ node.parent_id ].children.push( node.id );
    };

    var idx = 0;
    var visited = {};

    for(var key in f_map) {
      var index = f_map[key].index;
      var node = tree[index];
      if (!visited[node.id]) {
        node.nuid = idx++;
      } else {
        visited[node.id] = true;
      };
      if (f_map[key].children.length) {
        var children = f_map[key].children;
        for(var i = 0; i < children.length; i++) {
          var child_id = children[i];
          var child_idx = f_map[child_id].index;
          var child = tree[child_idx];
          child.nuid = idx++;
          visited[child.id] = true;
        };
      };
    };

    tree.sort(function(left, right) {
      return left.nuid - right.nuid;
    });

    return tree;
};

2 个答案:

答案 0 :(得分:4)

由于您将父指针表示为对父节点的id的引用,因此我首先将您的文件夹表示更改为对象表示:

var folders = {
    1: {parent_id: null, name: "Folder", path: null},
    ...
};

我添加了一个path字段,以便我可以记住以下递归函数的结果,以便找到文件夹的完整路径:

function path(node) {
    if (node.path !== null) return node.path;
    if (node.parent_id === null) {
        node.path = '/' + node.name;
    } else {
        node.path = path(folders[node.parent_id]) + '/' + node.name;
    }
    return node.path;
}

然后我们可以通过首先拉出我们想要排序的字段和对项目的引用来进行Schwartzian变换:

var keys = [];

Object.keys(folders).map(function (key) {
    var folder = folders[key];
    keys.push({path: path(folder), id: key});
});

然后我们可以对keys数组进行排序:

keys.sort(function (a, b) {
    var apath = a.path;
    var bpath = b.path;

    // probably the best way to compare folder paths..
    return apath.localeCompare(bpath);
});

最后我们可以通过遍历keys数组按照排序顺序生成文件夹:

var sorted_folders = keys.map(function (item) {
    return folders[item.id];  // .name; or maybe .path; ??
});

因为sorted_folders将是文件夹对象的列表,但根据注释,您可以在此步骤中轻松提取所需的属性。

答案 1 :(得分:1)

首先,递归并不慢。拥有你的武器库是一个很好的工具。它使解决某些问题变得更加容易。

这是一个应该解决它的算法。

1. If the graph can be a forest and not a tree
       create a new node root
       Make all roots in forest point to this root as parent
2. For every node, create an array (stack) of its children, call it c[i].
3. For each vertex v in tree
       c[v.parent].push(v)
4. u = root, i = 0
5. print u
6. while c[root] is not empty and u != root
       if c[u] is not empty
           u = pop(c[u])
           i++
           print tab i times
           print u
       if c[u] is empty and u != root
           u = u.parent
           i--