使用sql连接进行高效的广度优先搜索

时间:2017-06-04 17:46:16

标签: sql postgresql binary-search-tree breadth-first-search ecto

我正在处理二叉树。

所以我的数据库中有一个数据库表,每个节点都是最多2个其他节点的父节点。我有一个计划,有效地找到最少的节点(在给定节点下),它是少于2个其他节点的父节点。我正在寻找最开放的位置来换句话说。所以我将其作为广度优先搜索实现。但是我为每个节点调用数据库的方式效率很低。我基本上沿着树走下去,在每个级别上生成一个运行的节点列表,并检查每个节点是否是其他两个节点的父节点。

这是一张图表: enter image description here

如果你想看到代码,请点击这里:

  # breadth-first search
  def build_and_return_parent_id(breadth_list) do
        [ {node_id} | tail ] = breadth_list

        child_list = fetch_children_id(node_id)

        bc_list = tail ++ child_list

        case length(child_list) do
          x when x > 2 ->


            # recursion
            build_and_return_parent_id(bc_list)

          2 ->

            # recursion
            build_and_return_parent_id(bc_list)

          _ -> node_id
        end
  end

  def fetch_children_id(id) do
    Repo.all( from n in Node,
              where: n.parent_id == ^id,
              order_by: [asc: n.inserted_at],
              select: {n.id})
  end
end

所以不要这么低效 - 每个节点一个db调用 - 我在想,如何生成一个包含少于两个父节点的所有节点的列表,然后沿着树向下移动,每个级别使用一个db调用以获取该级别上所有节点的列表,然后简单地比较这两个列表。如果两个列表中都有匹配的ID,我发现一个节点下面有一个可用的点。

这是一张图表:

enter image description here

问题是我对sql查询几乎一无所知。我的猜测是,这可以通过桌面上的某种自联接来完成。

node_id   |  parent_id
----------------------
1         |  nil
2         |  1
3         |  1
4         |  2
5         |  2
6         |  3
7         |  4
8         |  5
9         |  6
10        |  3

所以无论如何,我确定这个方法是否有效,但是我似乎无法找到有关用于生成打开列表或级别的sql查询类型的任何信息。名单。

现在我想第二个查询非常简单。因为我们有一个开放列表,所以我们可以使用where-in- [list]子句。我认为第一个是我正在努力的那个。

如果您有任何可以指向或帮助的事情,您可以提供我真的很感激。

1 个答案:

答案 0 :(得分:2)

您可以添加列#extradepth并创建索引:

child_count

然后搜索基本上应该是:

create index nodes_depth_1child_idx on nodes(depth) where child_count=1;

您还应该创建可以维护这些值的触发器。这会稍微减慢插入操作,因为插入必须读取父节点select node_id from nodes where child_count=1 order by depth limit 1; 并更新父节点depth