C/C++学习笔记 Vantage Point Trees的C++实现

news2024/10/7 6:45:11

        下面代码是VP 树的 C++ 实现,递归search()函数决定是搜索左孩子、右孩子还是两个孩子。为了有效地维护结果列表,我们使用优先级队列。

 

// A VP-Tree implementation, by Steve Hanov. (steve.hanov@gmail.com)
// Released to the Public Domain
// Based on "Data Structures and Algorithms for Nearest Neighbor Search" by Peter N. Yianilos
#include <stdlib.h>
#include <algorithm>
#include <vector>
#include <stdio.h>
#include <queue>
#include <limits>

template<typename T, double (*distance)( const T&, const T& )>
class VpTree
{
public:
    VpTree() : _root(0) {}

    ~VpTree() {
        delete _root;
    }

    void create( const std::vector& items ) {
        delete _root;
        _items = items;
        _root = buildFromPoints(0, items.size());
    }

    void search( const T& target, int k, std::vector* results, 
        std::vector<double>* distances) 
    {
        std::priority_queue<HeapItem> heap;

        _tau = std::numeric_limits::max();
        search( _root, target, k, heap );

        results->clear(); distances->clear();

        while( !heap.empty() ) {
            results->push_back( _items[heap.top().index] );
            distances->push_back( heap.top().dist );
            heap.pop();
        }

        std::reverse( results->begin(), results->end() );
        std::reverse( distances->begin(), distances->end() );
    }

private:
    std::vector<T> _items;
    double _tau;

    struct Node 
    {
        int index;
        double threshold;
        Node* left;
        Node* right;

        Node() :
            index(0), threshold(0.), left(0), right(0) {}

        ~Node() {
            delete left;
            delete right;
        }
    }* _root;

    struct HeapItem {
        HeapItem( int index, double dist) :
            index(index), dist(dist) {}
        int index;
        double dist;
        bool operator<( const HeapItem& o ) const {
            return dist < o.dist;   
        }
    };

    struct DistanceComparator
    {
        const T& item;
        DistanceComparator( const T& item ) : item(item) {}
        bool operator()(const T& a, const T& b) {
            return distance( item, a ) < distance( item, b );
        }
    };

    Node* buildFromPoints( int lower, int upper )
    {
        if ( upper == lower ) {
            return NULL;
        }

        Node* node = new Node();
        node->index = lower;

        if ( upper - lower > 1 ) {

            // choose an arbitrary point and move it to the start
            int i = (int)((double)rand() / RAND_MAX * (upper - lower - 1) ) + lower;
            std::swap( _items[lower], _items[i] );

            int median = ( upper + lower ) / 2;

            // partitian around the median distance
            std::nth_element( 
                _items.begin() + lower + 1, 
                _items.begin() + median,
                _items.begin() + upper,
                DistanceComparator( _items[lower] ));

            // what was the median?
            node->threshold = distance( _items[lower], _items[median] );

            node->index = lower;
            node->left = buildFromPoints( lower + 1, median );
            node->right = buildFromPoints( median, upper );
        }

        return node;

        下面是具体的调用,需要用到下面的数据

#include "VpTree.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <stdint.h>
#include <string>
#include <string.h>
#include <math.h>

#define DIM 200
#define NUM 32000

void QueryPerformanceCounter( uint64_t* val )
{
    timeval tv;
    struct timezone tz = {0, 0};
    gettimeofday( &tv, &tz );
    *val = tv.tv_sec * 1000000 + tv.tv_usec;
}

struct Point {
    std::string city;
    double latitude;
    double longitude;
};

double distance( const Point& p1, const Point& p2 )
{
    double a = (p1.latitude-p2.latitude);
    double b = (p1.longitude-p2.longitude);
    return sqrt(a*a+b*b);
}

struct HeapItem {
    HeapItem( int index, double dist) :
        index(index), dist(dist) {}
    int index;
    double dist;
    bool operator<( const HeapItem& o ) const {
        return dist < o.dist;   
    }
};

void linear_search( const std::vector<Point>& items, const Point& target, int k, std::vector<Point>* results, 
    std::vector<double>* distances) 
{
    std::priority_queue<HeapItem> heap;
    for ( int i = 0; i < items.size(); i++ ) {
        double dist = distance( target, items[i] );
        if ( heap.size() < k || dist < heap.top().dist ) {
            if (heap.size() == k) heap.pop();
            heap.push( HeapItem( i, dist ) );
        }
    }

    results->clear();
    distances->clear();
    while( !heap.empty() ) {
        results->push_back( items[heap.top().index] );
        distances->push_back( heap.top().dist );
        heap.pop();
    }

    std::reverse( results->begin(), results->end() );
    std::reverse( distances->begin(), distances->end() );
}

int main( int argc, char* argv[] ) {
    std::vector<Point> points;
    printf("Reading cities database...\n");
    FILE* file = fopen("cities.txt", "rt");
    for(;;) {
        char buffer[1000];
        Point point;
        if ( !fgets(buffer, 1000, file ) ) {
            fclose( file );
            break;
        }
        point.city = buffer;
        size_t comma = point.city.rfind(",");
        sscanf(buffer + comma + 1, "%lg", &point.longitude);
        comma = point.city.rfind(",", comma-1);
        sscanf(buffer + comma + 1, "%lg", &point.latitude);
        //printf("%lg, %lg\n", point.latitude, point.longitude);
        points.push_back(point);
        //if(points.size()>50000)break;
    }
    
    VpTree<Point, distance> tree;
    uint64_t start, end;
    QueryPerformanceCounter( &start );
    tree.create( points );
    QueryPerformanceCounter( &end );
    printf("Create took %d\n", (int)(end-start));

    Point point;
    point.latitude = 43.466438;
    point.longitude = -80.519185;
    std::vector<Point> results;
    std::vector<double> distances;

    QueryPerformanceCounter( &start );
    tree.search( point, 8, &results, &distances );
    QueryPerformanceCounter( &end );
    printf("Search took %d\n", (int)(end-start));

    for( int i = 0; i < results.size(); i++ ) {
        printf("%s %lg\n", results[i].city.c_str(), distances[i]);
    }

    printf("---\n");
    QueryPerformanceCounter( &start );
    linear_search( points, point, 8, &results, &distances );
    QueryPerformanceCounter( &end );
    printf("Linear search took %d\n", (int)(end-start));

    for( int i = 0; i < results.size(); i++ ) {
        printf("%s %lg\n", results[i].city.c_str(), distances[i]);
    }


    return 0;
}

        上面程序运行时候的

http://stevehanov.ca/blog/cities.txt.gzicon-default.png?t=N6B9http://stevehanov.ca/blog/cities.txt.gz

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/848590.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】开源:tinyxml2解析库配置使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍tinyxml2解析库配置使用。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;…

路由器中DMZ、UPnP、Port Forwarding等功能介绍与使用

目录 一、DMZ功能1.1 概念1.2 验证测试方式 二、UPnP功能2.1 概念2.2 验证测试方法 三、Port Forwarding功能3.1 概念3.2 验证测试方法3.3 NAT相关 一、DMZ功能 1.1 概念 **DMZ&#xff08;Demilitarized Zone&#xff09;**是指位于防火墙内部网络&#xff08;LAN&#xff0…

Sentinel整合Spring Cloud Gateway、Zuul详解

Sentinel 支持对 Spring Cloud Gateway、Zuul 等主流的 API Gateway 进行限流。 Sentinel 1.6.0 引入了 Sentinel API Gateway Adapter Common 模块&#xff0c;此模块中包含网关限流的规则和自定义 API 的实体和管理逻辑&#xff1a; GatewayFlowRule&#xff1a;网关限流规则…

公文校对要点:确保准确性和规范性

公文校对是确保文档准确性和规范性的重要步骤。以下是公文校对的要点&#xff1a; 1.拼写和语法检查&#xff1a;仔细检查文档中的拼写错误和语法错误。确保词语的正确拼写&#xff0c;并使用正确的语法结构和标点符号。 2.信息准确性&#xff1a;核对文档中的事实和数据&#…

AP51656 电流采样降压恒流驱动IC RGB PWM深度调光 LED电源驱动

产品描述 AP51656是一款连续电感电流导通模式的降压恒流源&#xff0c;用于驱动一颗或多颗串联LED 输入电压范围从 5 V 到 60V&#xff0c;输出电流 可达 1.5A 。根据不同的输入电压和 外部器件&#xff0c; 可以驱动高达数十瓦的 LED。 内置功率开关&#xff0c;采用电流采样…

Java ThreadPoolExecutor,Callable,Future,FutureTask 详解

目 录 一、ThreadPoolExecutor类讲解 1、线程池状态 五种状态 2、ThreadPoolExecutor构造函数 2.1&#xff09;线程池工作原理 2.2&#xff09;KeepAliveTime 2.3&#xff09;workQueue 任务队列 2.4&#xff09;threadFactory 2.5&#xff09;handler 拒绝策略 3、常…

递归在树的深度遍历中的运用

树的深度遍历 对于树这种数据结构&#xff0c;之前一直使用的是层次遍历&#xff0c;也就是广度优先搜索的方式&#xff08;BFS&#xff09;&#xff1b;对于树的遍历&#xff0c;还可以进行深度优先搜索&#xff08;DFS&#xff09;。 而结合递归&#xff0c;树的深度优先搜索…

【硬件设计】模拟电子基础三--集成运算放大电路

模拟电子基础三--集成运算放大电路 一、集成运算放大器1.1 定义、组成与性能1.2 电流源电路1.3 差动放大电路1.4 理想运算放大器 二、集成运算放大器的应用2.1 反向比例运算电路2.2 同向比例运算电路2.3 反向加法运算电路2.4 反向减法运算电路2.5 积分运算电路2.6 微分运算电路…

vivado tcl创建工程和Git管理

一、Tcl工程创建 二、Git版本管理 对于创建完成的工程需要Git备份时&#xff0c;不需要上传完整几百或上G的工程&#xff0c;使用tcl指令创建脚本&#xff0c;并只将Tcl脚本上传&#xff0c;克隆时&#xff0c;只需要克隆tcl脚本&#xff0c;使用vivado导入新建工程即可。 优…

最详细,手机APP测试-ADB命令总结大全,你要的都在这...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 adb是什么&#x…

系统集成项目成本管理

在项目中&#xff0c;成本是指项目活动或其组成部分的货币价值或价格&#xff0c;包括为实施、完成或创造该活动或其组成部分所需资源的货币价值。具体的成本一般包括直接工时、其他百接费用、间接工时、其他间接费用以及采购价格。 项目全过程所耗用的各种成本的总和为项目成本…

无数资深果粉称之为 Mac 装机必备软件的 ——CleanMyMac X

它就是被无数资深果粉称之为 Mac 装机必备软件的 ——CleanMyMac X。或许你没用过它&#xff0c;但是大概率你身边一定有它的资深用户&#xff0c;作为 MacPaw 旗下的老牌清理软件&#xff0c;在全球已经拥有超过 2500 万次的下载量。 它有着五大强悍的功能&#xff0c;可以帮…

超融合基础架构 (HCI) 监控

什么是超融合基础架构 &#xff08;HCI&#xff09; 超融合基础架构 &#xff08;HCI&#xff09; 是一种软件定义的基础架构技术&#xff0c;它将计算、虚拟化和网络功能全部整合到一个设备中。超融合基础架构 &#xff08;HCI&#xff09; 解决方案使用软件和 x86 服务器来取…

【Linux命令详解 | less命令】Linux系统中用于分页显示文件内容的命令

文章标题 简介一&#xff0c;参数列表二&#xff0c;使用介绍1. 分页显示文件内容2. 搜索关键词3. 显示行号4. 显示特定内容5. 只显示匹配行6. 忽略大小写搜索7. 输出到文件8. 动态查看文件增长9. 开启对二进制文件的支持10. 显示控制字符11. 忽略键盘输入12. 显示百分比进度条…

深度学习环境安装依赖时常见错误解决

1.pydantic 安装pydantic时报以下错误&#xff1a; ImportError: cannot import name Annotated from pydantic.typing (C:\Users\duole\anaconda3\envs\vrh\lib\site-packages\pydantic\typing.py) 这个是版本错误&#xff0c;删除装好的版本&#xff0c;重新指定版本安装就…

设计模式——设计模式以及六大原则概述

设计模式代表有经验的面向对象软件开发人员使用的最佳实践。 设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。 这些解决方案是由许多软件开发人员在相当长的时间内通过试错获得的。 什么是 GOF&#xff08;四人帮&#xff0c;全拼 Gang of Four&#xff09…

微信QQ链接防红屏障源码页面

一、作用&#xff1a;使用跳转到浏览器方式&#xff0c;防止自己链接在微信和QQ等软件无法打开。 微信QQ链接防红屏障.zip - 蓝奏云文件大小&#xff1a;2.8 M|https://wwwf.lanzout.com/iwrWS14sfzcb 二、图片&#xff1a;​ 六、安装与使用&#xff1a;上传到空间即可 使用…

Dubbo是干嘛的,Dubbo原理和机制,Dubbo的核心组件

目录 一、介绍1、Dubbo是什么2、为什么需要Dubbo3、Dubbo的特性 二、 Dubbo的核心概念1、暴露和引用&#xff08;Export and Refer&#xff09;2、服务提供者和服务消费者3、注册中心4、负载均衡5、集群容错 三、Dubbo的架构1、服务提供者和服务消费者之间的通信流程2、Dubbo的…

NR CSI(六) CSI reporting using PUCCH

之前NR CSI(二) the workflow of CSI report有对CSI report的相关流程进行介绍&#xff0c;而这篇主要看下CSI reporting over PUCCH的相关规定。 CSI report在PUCCH上传输的场景如上表红色字体&#xff0c;有三种场景&#xff0c;具体的对应的是Periodic 和Semi-Persistent CS…

sentinel核心流程源码解析

sentinel的处理槽(ProcessorSlot) 可以说&#xff0c;sentinel实现的各种功能就是由各处理槽完成的 ,ProcessorSlot定义了四个方法&#xff1a; 当进入该处理槽时触发该方法 处理完 entry方法之后触发该方法 退出该处理槽时触发该方法 exit方法处理完成时触发该方法 sentinel的…