【问题标题】:Search coordinates in a binary not working correctly在二进制文件中搜索坐标无法正常工作
【发布时间】:2021-11-30 16:06:50
【问题描述】:

我需要在二叉树中插入很多坐标,有时还要合并它们。我正在测试该程序一段时间,并注意到搜索功能有时不起作用。

在这个例子中,我创建了两棵二叉树,将它们合并并搜索了一些坐标,但是没有找到插入到树中的坐标:

First tree:
0 2
9 8
7 0
6 0
Second tree:
3 2
8 5
4 1
5 6
Merged trees:
3 2
8 5
4 1
5 6
0 2
9 8
7 0
6 0
VALUES 8 and 5 NOT FOUND

有人可以帮我解决这个问题吗?

代码如下:

function binarytree()
{
  this.root = null;
  this.add = function()
  {
    var node = {
                 x : j,
                 y : i,
                 left : null,
                 right : null
               };
    var current;
    if (this.root == null) this.root = node;
      else {
             current = this.root;
             while (1)
             {
               if (i < current.y || j < current.x) {
                  if (current.left == null) {
                      current.left = node;
                      break;
                  }
                   else current = current.left;
               }
               else if (i > current.y || j > current.x) {
                       if (current.right == null) {
                           current.right = node;
                           break;
                       }
                       else current = current.right;
                    }
                    else break;
             }
           }
  }

  this.search = function(tree, i, j) {
    var found = false;
    current = tree.root;
    while (!found && current) {
      if (i < current.y || j < current.x) current = current.left;
        else if (i > current.y || j > current.x) current = current.right;
          else found = true;
    }
    return found;
  }

  this.print = function(no)
  {
    if (no)
    {
      this.print(no.left);
      this.print(no.right);
      console.log(no.x, no.y);
    }
  }
}

function merge(tree, tree2) {
    if (tree2.x < tree.x || tree2.y < tree.y) {
        if (tree.left) {
            this.merge(tree.left, tree2);
        } else {
            tree.left = tree2;
        }
    } else {
        if (tree.right) {
            this.merge(tree.right, tree2);
        } else {
            tree.right = tree2;
        }
    }
}
  var i, j;
  var tree = new binarytree();
  var tree2 = new binarytree();

  for (x = 0; x < 4; x++)
  {
     i = Math.floor(Math.random() * 10);
     j = Math.floor(Math.random() * 10);
     tree.add();
  }

  for (x = 0; x < 4; x++)
  {
     i = Math.floor(Math.random() * 10);
     j = Math.floor(Math.random() * 10);
     tree2.add();
  }

  console.log("First tree:");
  tree.print(tree.root);
  console.log("Second tree:");
  tree2.print(tree2.root);

  merge(tree.root,tree2.root);
  console.log("Merged trees:");
  tree.print(tree.root);

  if (tree.search(tree, i, j) == true) console.log("FOUND VALUES " + j + " AND " + i);
    else console.log("VALUES " + j + " AND " + i + " NOT FOUND");

【问题讨论】:

    标签: javascript coordinates binary-tree


    【解决方案1】:

    正如您在deleted question 中已经提到的,您需要为此使用 KD 树,因为普通的二叉搜索树适用于一维值,而不是二维值。

    您的代码中有几个问题:

    • 将点分成 2 个类别的方式不是传递操作。假设您在一棵树中有两个点:(0, 0) 和 (10, -5),那么第二个点将存储在根的 left 属性中。这是因为 -5 小于 0。现在我们有第二棵树,它有两个点:(4, 4) 和 (10, -5)。出于同样的原因,这棵树将具有与第一棵树相同的结构。您的merge 函数会将第二棵树放在第一棵树根的right 属性中。这是因为 (4, 4) 被认为是 (0, 0) 的“右”。现在注意这是如何不一致的:现在我们有一个 (10, -5) 位于合并树的左右子树中!发生这种情况是因为您比较点的方式不是传递比较。

    • 以上几点是主要问题,但还要注意if (i &lt; current.y || j &lt; current.x) 平均适用于 75% 的情况。这是这种比较方法不正确的第二个原因。

    在 KD 树中比较 2D 点的方法是交替与 X 坐标或 Y 坐标进行比较。因此,在树的顶层,您将比较 Y 坐标来决定是向左还是向右,在下一层您将比较 X 坐标。然后再更深一层,您将再次比较 Y 坐标,...等等。

    其他一些评论:

    • 使用class语法
    • 也为节点实例创建构造函数
    • 不要在方法中打印,而是定义一个生成器来生成所有值,并定义一个toString 方法并在主程序中打印该字符串。
    • 避免使用全局变量:您的add 方法应该将ij 作为参数,并且您应该始终声明变量(您没有在search 中使用var current,也没有在x 中使用x和主代码中的y):如果您想编写可靠的代码,这一点至关重要。考虑使用"use strict",它会提醒您此类问题。
    • addsearch 将使用类似的方式在树中导航,因此将它们共同的代码放在一个单独的函数中,我们可以称之为 locate
    • 据我所知,没有办法像您想象的那样合并 KD 树,您可以决定将第二棵树的“其余部分”放在第一棵树的叶节点下。所以我建议只迭代第二棵树的节点并在第一棵树中一个接一个地插入它们。

    这是建议的代码:

    "use strict"; // To help avoid all kinds of problems
    
    class Node { // Use a class for creating node instances
        constructor(i, j) {
            this.x = i;
            this.y = j;
            this.left = null;
            this.right = null;
        }
        * inorder() { // Generator to visit all nodes
            if (this.left) yield * this.left.inorder();
            yield [this.x, this.y];
            if (this.right) yield * this.right.inorder();
        }
    }
    
    class BinaryTree {
        constructor() {
            this.root = null;
        }
        locate(i, j) { // A common function to avoid code repetition
            if (this.root == null) return [null, "root"];
            let current = this.root;
            let axis = "x";
            let otherAxis = "y";
            while (true) {
                // alternate the axis:
                [axis, otherAxis, i, j] = [otherAxis, axis, j, i];
                if (i < current[axis]) {
                    if (current.left == null) return [current, "left"];
                    current = current.left;
                } else if (i > current[axis] || j != current[otherAxis]) {
                    if (current.right == null) return [current, "right"];
                    current = current.right;
                } else { // point is already in the tree
                    return [current, "equal"]; 
                }
            }
        }
        add(i, j) { // this method should have parameters
            if (this.root == null) {
                this.root = new Node(i, j); // Use constructor for creating node
            } else {
                const [current, side] = this.locate(i, j);
                if (side !== "equal") {
                    current[side] = new Node(i, j);
                }
            }
        }
        search(i, j) {
            const [_, side] = this.locate(i, j);
            return side === "equal";
        }
        * inorder() {
            if (this.root) yield * this.root.inorder();
        }
        mergeWith(otherTree) {
            // Insert all the other nodes one by one:
            for (let point of otherTree.inorder()) {
                this.add(...point);
            }
        }
        toString() { // Don't print, but produce string
            return JSON.stringify(Array.from(this.inorder()));
        }
    }
    
    const tree = new BinaryTree();
    for (const point of [[0, 2], [9, 8], [7, 0], [6, 0]]) tree.add(...point);
    const tree2 = new BinaryTree();
    for (const point of [[3, 2], [8, 5], [4, 1], [5, 6]]) tree2.add(...point);
    console.log("First tree:");
    console.log(tree.toString());
    console.log("Second tree:");
    console.log(tree2.toString());
    tree.mergeWith(tree2);
    console.log("Merged trees:");
    console.log(tree.toString());
    
    // Check that all points are found:
    for (const point of tree.inorder()) {
        console.log(...point, tree.search(...point));
    }

    【讨论】:

    • trincot,一次又一次,谢谢!你太专业了!我删除了这个问题,因为我认为没有人会帮助我,并且我收到了代码识别的批评,所以我想到了这个。再次非常感谢!如果我能为你做点什么,你可以跟我一起算!
    猜你喜欢
    • 2013-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-25
    • 2020-10-25
    • 1970-01-01
    • 2013-04-23
    相关资源
    最近更新 更多