从选定的叶子开始克隆树的部分

时间:2017-10-03 17:56:16

标签: javascript algorithm graph tree

我按如下方式构建节点对象的Tree结构:

function Node(parent) {
    this.parent = parent;
    this.selected = false;
    this.children = [];
}

Node.prototype.addChild = function () {
    var l = this.children.push(new Node(this));
    return this.children[l-1];
};

Node.prototype.bfs = function(callback) {
    var queue=[this], n;
    while(queue.length > 0) {
        n = queue.shift();
        callback(n);
        if(n.children.length == 0) continue;
        for (var i = 0; i< n.children.length; i++) {
            queue.push(n.children[i]);
        }
    }
};

var root = new Node(null);
var nodeA = root.addChild();
var nodeB = root.addChild();
var nodeAA = nodeA.addChild();
var nodeAB = nodeA.addChild();
var nodeBA = nodeB.addChild();
var nodeBB = nodeB.addChild();

现在,我选择了一些节点:

nodeAA.selected = true;

我能够通过BFS找到所选节点:

root.bfs(function(node){
    console.log(node, node.selected);
});

...并且很容易标记为选择所有相应的父节点,直到根:

var n = node;
do {
    n.selected = true;
    n = n.parentNode;
} while (n);

现在,我需要使用选定的叶子和相应的父节点创建初始Tree结构的克隆,但是我无法将新的子节点重新分配给各自的新父节点。

尝试使用JSON.stringify()会导致循环引用错误。

如何只使用选定叶子的分支重建我的初始树的克隆?

1 个答案:

答案 0 :(得分:0)

假设可以修剪现有树以排除未选择的叶子路径,In [591]: tidx = pd.date_range('2017-01-01', periods=12, freq='MS') In [592]: (df.set_index(['Month', 'User'])['count'].unstack() .reindex(tidx) .fillna(0) .unstack().reset_index() .rename(columns={'level_1': 'Month', 0: 'count'})) Out[592]: User Month count 0 A 2017-01-01 2.0 1 A 2017-02-01 0.0 2 A 2017-03-01 2.0 3 A 2017-04-01 0.0 4 A 2017-05-01 2.0 5 A 2017-06-01 0.0 6 A 2017-07-01 0.0 7 A 2017-08-01 0.0 8 A 2017-09-01 2.0 9 A 2017-10-01 0.0 10 A 2017-11-01 0.0 11 A 2017-12-01 0.0 12 B 2017-01-01 5.0 13 B 2017-02-01 0.0 14 B 2017-03-01 0.0 15 B 2017-04-01 0.0 16 B 2017-05-01 5.0 17 B 2017-06-01 0.0 18 B 2017-07-01 0.0 19 B 2017-08-01 0.0 20 B 2017-09-01 0.0 21 B 2017-10-01 0.0 22 B 2017-11-01 0.0 23 B 2017-12-01 0.0 将执行此操作。

缺点:

  1. 修改现有树
  2. 已修剪的子项仍将作为具有dfs值的children数组中的条目存在。可以通过使用支持null删除和插入
  3. 的数据结构来克服

    Psuedo Code

    O(1)

    假设是这样的。

    Prune-UnSelected-Leaf(root)
    
    if(root) == null return null
    
    if(root.children.length == 0) //Check if node is a Leaf
      if(root.selected)
        return root // Keep this node
      else 
        return null; // Ignore the node
    bool AnyChildSelected = false
    for(i : 1 to children.Length)
      var childSelectedNode = Prune-UnSelected-Leaf(children[i])
      if(childSelectedNode)
        AnyChildSelected = true
      root.children[i] = childSelectedNode
    
    if(AnyChildSelected == true || node.selected == true) // Keep the node
      return node
    else 
      return null; // Ignore the node
    

    运行算法后,未选择的路径将设置为null,并且看起来像这样

            Root Node
            /   |    \
           /    |     \
        A(T)   B(F)    C(F)
        /              /  
      D(F)            E(T)
    

    您还可以修改上述算法以克隆树,而无需修改现有树。

    重载 Root Node / X \ Return A / X(null) \ Return C A(T) B(F) C(F) X / X Return null / Return E D(F) E(T) 以将现有子节点附加到父

    addChild

    addChild(child) child.parent = this l = this.children.push(child); return this.children[l-1]; 成为一个函数,它接受一个节点并使用与该节点相关的信息创建一个深层副本,但初始化Clone-Node(node)parentchildren的空/默认值属性

    selected