| 赞 | 0  | 
 
| VIP | 1 | 
 
| 好人卡 | 0 | 
 
| 积分 | 1 | 
 
| 经验 | 6986 | 
 
| 最后登录 | 2013-3-15 | 
 
| 在线时间 | 55 小时 | 
 
 
 
 
 
Lv1.梦旅人 v 
	- 梦石
 - 0 
 
        - 星屑
 - 50 
 
        - 在线时间
 - 55 小时
 
        - 注册时间
 - 2007-12-19
 
        - 帖子
 - 99
 
 
 
 | 
	
加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员  
 
x
 
 本帖最后由 veal 于 2009-8-7 04:14 编辑  
 
VP树是由Peter N. Yianilos 在1993年的论文Data Structures and Algorithms for Nearest Neighbor Search in General Metric Spaces 中提出的一种搜索度量空间(Metric Space)的二叉搜索树。 
 
用途: 
最邻近搜索。任何在度量空间的数据都可以生成VP树进行搜索。 
度量空间定义(来自http://zh.wikipedia.org/wiki/%E5%BA%A6%E9%87%8F%E7%A9%BA%E9%97%B4): 
   1. d(x, y) ≥ 0 (非负性) 
   2. d(x, y) = 0 当且仅当 x = y (不可区分者的同一性) 
   3. d(x, y) = d(y, x) (对称性) 
   4. d(x, z) ≤ d(x, y) + d(y, z) (三角不等式)。 
在RM中可能的应用: 
1. 坐标系就是度量空间,可用于给出一个点,寻找一定半径内的所有点(测试工程的测试就是这个) 
2. 拼写纠错,词汇之间的编辑距离也是度量距离 
 
优点: 
搜索复杂度:O(log(N)),当然随着搜索半径的增加,复杂度会增加。例如你有一本10万字的词典,给你一个词,搜索所有只差一个字母的词,全部词遍历一次的话要访问10万个词,用VP树最优化的情况下只需要访问(log(100000)/log(2)约等于17)个词。 
 
缺点: 
由于VP树是静态的,无法在其身上实现插入和删除操作。 
大量距离查询操作,所以最好能缓存距离查询。 
更先进的最邻近搜索算法请参考下面的链接或Google。 
 
扩展阅读: 
http://en.wikipedia.org/wiki/Nearest_neighbor_search 
 
下面是VP树的实现代码,不保证优化,仅供参考:- #==============================================================================
 
 - # ■ VPTree
 
 - #------------------------------------------------------------------------------
 
 - #   用于metric space的搜索树  
 
 - #==============================================================================
 
  
- class VPTreeNode
 
 -   #--------------------------------------------------------------------------
 
 -   # ● 实例变量
 
 -   #--------------------------------------------------------------------------
 
 -   attr_accessor :parent, :left, :right, :data, :threshold, :dist_proc
 
 -   #--------------------------------------------------------------------------
 
 -   # ● 初始化
 
 -   #--------------------------------------------------------------------------
 
 -   def initialize(args, &block)
 
 -     # 如果传递了块
 
 -     if block != nil
 
 -       @dist_proc = block
 
 -     # 没有传递块的话就用distance(other)
 
 -     else
 
 -       @dist_proc = Proc.new{|a, b|
 
 -         a.distance(b)
 
 -       }
 
 -     end
 
 -     # 大于两个数据的话,随机取一个数据为这个节点的data(这里取中间一个)
 
 -     # 用其他数据到这个数据的距离的中位数作为threshold,
 
 -     # 小于等于threshold加入左子树,大于threshold加入右子树
 
 -     if args.size > 2
 
 -       median = args.size / 2
 
 -       @data = args.delete_at(median)
 
 -       args.sort!{|a, b| @dist_proc.call(@data, a) <=>  @dist_proc.call(@data, b)}
 
 -       @threshold =  @dist_proc.call(@data, args[median - 1])
 
 -       @left = VPTreeNode.new(args[0, median], &@dist_proc)
 
 -       @left.parent = self
 
 -       @right = VPTreeNode.new(args[median, args.size - median], &@dist_proc)
 
 -       @right.parent = self
 
 -     # 如果只剩2个数据的话
 
 -     elsif args.size == 2
 
 -       @data = args[0]
 
 -       @threshold =  @dist_proc.call(@data, args[1])
 
 -       @left =  VPTreeNode.new(args[1, 1], &@dist_proc)
 
 -       @left.parent = self
 
 -     # 只剩一个数据的话
 
 -     elsif args.size == 1
 
 -       @data = args[0]
 
 -     end
 
 -   end
 
 -   #--------------------------------------------------------------------------
 
 -   # ● 是否叶节点
 
 -   #--------------------------------------------------------------------------
 
 -   def leaf?
 
 -     return (@left == nil && @right == nil)
 
 -   end
 
 -   #--------------------------------------------------------------------------
 
 -   # ● 输出
 
 -   #--------------------------------------------------------------------------
 
 -   def inspect
 
 -     return "<Node: #{@data.inspect}, @threshold = #{@threshold}>"
 
 -   end
 
 -   #--------------------------------------------------------------------------
 
 -   # ● 检查节点有效性
 
 -   #--------------------------------------------------------------------------
 
 -   def node_valid?
 
 -     if @left != nil
 
 -       @left.each{|child_data|
 
 -         if @dist_proc.call(@data, child_data) > @threshold
 
 -           return false
 
 -         end
 
 -       }
 
 -     end
 
 -     if @right != nil
 
 -       @right.each{|child_data|
 
 -       if @dist_proc.call(@data, child_data) <= @threshold
 
 -         return false
 
 -       end
 
 -       }
 
 -     end
 
 -     return true
 
 -   end
 
 -   #--------------------------------------------------------------------------
 
 -   # ● 检查树有效性
 
 -   #--------------------------------------------------------------------------
 
 -   def valid?
 
 -     each{return false if !node_valid?}
 
 -     return true
 
 -   end
 
 -   #--------------------------------------------------------------------------
 
 -   # ● 迭代小于等于dist的所有data
 
 -   #--------------------------------------------------------------------------
 
 -   def each_within(sample, dist, &block)
 
 -     # 获得sample到data的距离
 
 -     sample_dist = @dist_proc.call(@data, sample)
 
 -     # 如果这个距离小于dist,就迭代data
 
 -     if sample_dist <= dist
 
 -       yield(@data)
 
 -     end
 
 -     
 
 -     # 需要迭代左子树的情况
 
 -     if @left != nil && @threshold + dist >= sample_dist
 
 -       @left.each_within(sample, dist, &block)
 
 -     end
 
 -     # 需要迭代右子树的情况
 
 -     if @right != nil && sample_dist + dist  > @threshold
 
 -       @right.each_within(sample, dist, &block)
 
 -     end
 
 -   end
 
 -   #--------------------------------------------------------------------------
 
 -   # ● 迭代
 
 -   #--------------------------------------------------------------------------
 
 -   def each(&block)
 
 -     yield(@data)
 
 -     @left.each(&block) if @left != nil
 
 -     @right.each(&block) if @right != nil
 
 -   end
 
 - end
 
  复制代码 测试工程下载: 
 
VPTree.rar
(729.91 KB, 下载次数: 123)
 |   
 
评分
- 
查看全部评分
 
 
 
 
 
 |