zoukankan      html  css  js  c++  java
  • 树形结构的节点搜索优化

    介绍

    树形结构具有在程序中普遍性。以XML为例,是一个树形的结构;其提供的XPath,给予了全局定位每一个节点的能力。本文针对这个操作,讨论性能上的优化。分析过程采用典型的自底向上的方式:基本算法设计、算法性能考虑以及对象接口设计。

    基本设计

    简化起见,定义Path:<n1, n2, …, nk>。nj可以是常量,代表可以借助索引来加速的情况;也可以是通配符,代表只能遍历的情况。

    tree.find(Path xp)

                node <= tree.root

                For i = 1 to k

                            node <= node.find(xp[i]) // node is a set if xp[i] is wildcard

                Return node

    以node.find为基本操作,这个算法时间复杂度为O(N),N为Xpath长度。以tree的节点node为基本存储单位,这个算法空间复杂度为O(N),如果xp为常数,N为Xpath长度;如果所有xp[i]为通配符,N为tree节点的总个数。

    性能考虑

    当tree.find被调用M次的时候,这个算法的时间复杂度为M*O(N)。通过分析,如果考虑调用之间的相关度,可以有效地提高算法效率。

    1、   对于常量xp,如果两个相邻的xp之间,相同节点的个数在0到N之间平均分布,那么增加N个基本存储单位作为缓存,时间复杂度会下降为M/2*O(N)。

    2、  对于变量xp,事实上搜索结果是节点集合,基本上仍然有上面的结论。值得注意的是此时N为tree节点的总个数。当N比较大的时候,这种缓存技术的空间复杂度并不令人满意。

    为了处理好第二种情况,对现实情况进行进一步分析:

    1、   一般N比M大很多

    2、  如果xp开始几个节点是常量。这是一种在给定节点下的无条件遍历,借助索引的node.find的次数小于xp的长度。这种情况下,多次tree.find调用可以参照常量xp优化。

    3、  如果xp开始几个节点是通配符,中间几个节点是常量。最差的情况就是遍历所有的节点(具有规定长度的Path),然后一个一个地判断每个路径是否与中间结点匹配。有些应用里面,可以根据后面几个节点名字得到前面某些节点的范围。此时要在遍历算法中增加这些范围的判断,如果这种判断的代价小于node.find的话。

    4、  第3种情况下,多次tree.find调用合并成一次,可以共用遍历,虽不减少时间复杂度,但是减少了节点的内存访问,从而提高性能。

    接口设计

    最简单的接口就是set_of_node tree.find(Path xp)

    注意到返回的节点可能比较多,可以把调用改成多次返回一个节点,即node tree.find(Path xp),返回NULL时一次搜索结束。这样可以削减空间复杂度,但是算法内部需要一个迭代器的设计模式。

    考虑到多次变量xp的可合并性,还可以改成两个函数,调用序列如下:

    { { define_path_to_search(xp); } { tree.find(); } }

  • 相关阅读:
    [转]java常量池理解总结
    设计数据库时使用外键吗
    ajax 下载文件
    CentOS6.4配置163的yum源
    Xms Xmx PermSize MaxPermSize 区别
    [转]基于java的程序OutOfMemory问题的解决及Xms/Xmx/Xss的解释和应用
    Java Web Services面试
    java 单例模式
    Spring和MyBatis整合
    Spring核心概念
  • 原文地址:https://www.cnblogs.com/liuyunfeng/p/2721195.html
Copyright © 2011-2022 走看看