替换树结构中的根

时间:2015-09-25 09:46:14

标签: javascript jquery node.js tree

我有以下树,可以将其称为Tree One

        1
       / \
      /   \
     2     3
    /
   /
  4

现在我想用2替换根节点。然后上面的树将变成这样的东西。让我们称之为Tree Two

        2
       / \
      /   \
     4     1
            \
             \
              3

如何按上述方法为数组输入实现上述内容?

更新

我已经尝试过使用Linkedlist。但是,它低于上述输入(即数组)。

    function replaceRootNode(tree, x) {
      var y = x.left;
      x.left = y.right;
      if (y.right) {
        y.right.parent = x;
      }
      y.parent = x.parent;
      if (!x.parent) {
        tree.root = y;
      } else {
        if (x === x.parent.left) {
          x.parent.left = y;
        } else {
          x.parent.right = y;
        }
      }
      y.right = x;
      x.parent = y;
    }

更新2

我使用likeslist的上述解决方案基于Splay Tree。但我需要它来进行数组输入。

2 个答案:

答案 0 :(得分:2)

您的定义不完整,因此我添加了以下定义:

  • 新选择的根不必是当前根的直接子节点(即您可以直接从状态1进入状态3)。
  • 如果新选择的根同时具有左右子节点,则其中一个将分配给其前一个父节点。

我所做的是首先将其转换为结构化的json并在那里进行操作。我使用lodash来使代码更清晰。

请注意,我的代码具有从您的格式转换为json并返回的功能。当您查看代码时,请确保打开控制台,此外,您还有一些更复杂的树木样本。注释掉,你也可以尝试一下。



// var tree = [1, [2, [4], [5]], [3]];
var tree = [1, [2, [4]],
  [3]
];
// var tree = [1, [2, [4, [5, [6,[7]]]]], [3]];

var zipTree = _.partial(_.zipObject, ['root', 'left', 'right']);
var toTree = _.flow(zipTree, _.partial(_.pick, _, _.identity));

function toTreeRecurse(data) {
  var result = toTree(data);
  if (_.isArray(result.left)) {
    result.left = toTreeRecurse(result.left);
  }
  if (_.isArray(result.right)) {
    result.right = toTreeRecurse(result.right);
  }
  return (result);
}

function toArrayRecurse(tree) {
  var result = [tree.root];
  if (tree.left) {
    result.push(toArrayRecurse(tree.left));
  }
  if (tree.right) {
    result.push(toArrayRecurse(tree.right));
  }
  return (result);
}

function findValueParent(tree, value) {
  if (!tree) {
    return (null);
  }
  var result;
  if (_.get(tree, 'left.root') === value) {
    return (tree);
  } else if (_.get(tree, 'right.root') === value) {
    return (tree);
  } else if (result = findValueParent(tree.left, value)) {
    return (result);
  } else if (result = findValueParent(tree.right, value)) {
    return (result);
  } else {
    return (null);
  }
}

function setRoot(tree, value) {
  var rootParent = findValueParent(tree, value);
  var newRoot;
  if (rootParent) {
    var fromSide, toSide;
    if (findValueParent(tree.left, value) || (_.get(tree, 'left.root') === value)) {
      fromSide = 'left';
      toSide = 'right';
    } else if (findValueParent(tree.right, value) || (_.get(tree, 'right.root') === value)) {
      fromSide = 'right';
      toSide = 'left';
    }
    newRoot = _.get(rootParent, fromSide);
    if (_.get(newRoot, toSide)) {
      _.set(rootParent, fromSide, _.get(newRoot, toSide));
    } else {
      delete rootParent[fromSide];
    }
    _.set(newRoot, toSide, tree);
    return (newRoot);
  } else {
    console.log('value does not exist');
    return (null);
  }
}
console.log('original: ', JSON.stringify(tree));
console.log('original as json tree: ', JSON.stringify(toTreeRecurse(tree)));
console.log('setting root to 2: ', JSON.stringify(toArrayRecurse(setRoot(toTreeRecurse(tree), 2))));
console.log('setting root to 4: ', JSON.stringify(toArrayRecurse(setRoot(toTreeRecurse(tree), 4))));

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js"></script>

<div>Demo, make sure you open the devtools to see the console print</div>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

我不相信有一种方法可以专门使用数组。链接列表绝对更适合您的问题。

因此,如果您只接受数组作为输入,则可以执行以下操作:

  1. 将输入数组转换为链接列表。
  2. 使用您提供的replaceRootNode功能替换节点。
  3. 将链表转换回数组。
  4. 这是我转换数组的代码示例:

    var arr = [2, [1, [3]], [4]];
    var tree = {
        root: null
    };
    
    arrayToList(arr, tree);
    console.log(tree);
    
    function arrayToList(array, tree){
        var node = {
            data: array[0],
            left: null,
            right: null
        };
        if (tree.root == null) {
            tree.root = node;
        }
        if(array[1] instanceof Array) {
            node.left = arrayToList(array[1], tree); 
        } else {
            node.left = array[1];
        }
        if(array[2] instanceof Array) {
            node.right = arrayToList(array[2], tree); 
        } else {
            node.right = array[2];
        }
        return node;
    }
    

    Fiddle(在控制台输出)。

    我正在使用Postorder遍历树,Left&gt; Right&gt; Root。因此,与上面的示例相比,它将输出镜像的树。

    如果您希望首先访问正确的节点,则可以执行以下简单编辑:Fiddle。虽然你通常总是在Right之前访问Left。

    无论如何,你可以用你的功能替换你的根节点(没有尝试过)。

    然后,您可以执行类似的功能将重新排列的树转换回数组。