Range Tree C++实现优化

继续对之前的版本 Range Tree C++实现 进行优化

优化点一:用shared_ptr取代static的点数组

优化点二:参考 https://tildesites.bowdoin.edu/~ltoma/teaching/cs3250-CompGeom/spring16/Lectures/cg-rangetrees.pdf
https://ima.udg.edu/~sellares/ComGeo/RangeTrees4Ms.pdf
只对所有点做一次y方向的排序,然后按照y方向顺序,再给左右子树一个按照y顺序排序好的数组

#ifndef RANGE_TREE_2D_H
#define RANGE_TREE_2D_H 1

#include "Point.h"
#include <vector>
#include <memory>

class RangeTree1D
{
    friend class RangeTree2D;

protected:
    RangeTree1D(std::shared_ptr<std::vector<FloatPoint>> &data);
    ~RangeTree1D();

    bool Build(std::vector<int>& idx);

    void RangeQuery(FloatPoint& query_low, FloatPoint& query_high,
        std::vector<int>& result_idx, float ylow, float yhigh);
    void TraversalInorder(std::vector<int>& result_idx);
    bool IsLeaf();

protected:
    int keypos_;
    RangeTree1D* lchild_;
    RangeTree1D* rchild_;

    std::shared_ptr<std::vector<FloatPoint>> data_;
};


class RangeTree2D
{
public:
    RangeTree2D(const std::vector<FloatPoint>& in_data);
    ~RangeTree2D();

    bool BuildTree();
    void RangeQuery(FloatPoint&query_low, FloatPoint&query_high,
        std::vector<int>& result_idx);

protected:
    RangeTree2D(std::shared_ptr<std::vector<FloatPoint>>& data);

    bool Build(std::vector<int>& x_idx, std::vector<int>& y_idx);
    void RangeQuery(FloatPoint& query_low, FloatPoint& query_high,
        std::vector<int>& result_idx, float xlow, float xhigh);
    bool IsLeaf();

protected:
    int keypos_;
    RangeTree2D* lchild_;
    RangeTree2D* rchild_;
    RangeTree1D* ytree_;
    // 所有子孙树都共用同一份数据
    std::shared_ptr<std::vector<FloatPoint>> data_;
};


#endif
#include "RangeTree2D.h"
#include <numeric>
#include <algorithm>

const float kXMin = -1000.0;
const float kXMax = 1000.0;
const float kYMin = -1000.0;
const float kYMax = 1000.0;

typedef bool (*CompFun)(const FloatPoint&, const FloatPoint&);

static bool xless(const FloatPoint &l, const FloatPoint &r)
{
    return l.x < r.x;
}

static bool yless(const FloatPoint& l, const FloatPoint& r)
{
    return l.y < r.y;
}

template <typename T>
std::vector<int> SortIndex(const std::vector<T>& data, bool (*comp)(const T&, const T&)) 
{
    // initialize original index locations
    std::vector<int> idx(data.size());
    std::iota(idx.begin(), idx.end(), 0);
    //    for(int i=0;i<v.size();i++)  idx[i]=i;
        
    // sort indexes based on comparing values in v
    sort(idx.begin(), idx.end(), [&data, &comp](size_t i1, size_t i2) {return (*comp)(data[i1], data[i2]); });

    return idx;
}

template <typename T>
std::vector<int> SortIndex(const std::vector<T>& data, std::vector<int>& idx, 
    bool(*comp)(const T&, const T&)) 
{
    // sort indexes based on comparing values in v
    sort(idx.begin(), idx.end(), [&data, &comp](int i1, int i2) {return (*comp)(data[i1], data[i2]); });

    return idx;
}

/////////////////////////////////////////////
// class RangeTree1D
/////////////////////////////////////////////

RangeTree1D::RangeTree1D(std::shared_ptr<std::vector<FloatPoint>>& data) :
    keypos_(-1), lchild_(NULL), rchild_(NULL),
    data_(data)
{
}

RangeTree1D::~RangeTree1D()
{
    if (lchild_)
        delete lchild_;
    if (rchild_)
        delete rchild_;
}

bool RangeTree1D::Build(std::vector<int>& idx)
{
    size_t n = idx.size();
    if (n == 0)
        return false;

    size_t pos = !(n % 2) ? n / 2 - 1 : (n - 1) / 2;
    keypos_ = idx[pos];

    if (n == 1)
    {
        this->lchild_ = NULL;
        this->rchild_ = NULL;
    }
    else
    {
        std::vector<int> left, right;
        
        left.assign(idx.begin(), idx.begin() + pos + 1);
        right.assign(idx.begin() + pos + 1, idx.end());

        this->lchild_ = new RangeTree1D(data_);
        lchild_->Build(left);
        this->rchild_ = new RangeTree1D(data_);
        rchild_->Build(right);
    }

    return true;
}

void RangeTree1D::RangeQuery(FloatPoint& query_low, FloatPoint& query_high,
    std::vector<int>& result_idx, float ylow, float yhigh)
{
    if (this->IsLeaf()) // hit the leaf level?
    {
        float leaf_x = (*data_)[keypos_].x;
        float leaf_y = (*data_)[keypos_].y;

        // count if point in range
        if (leaf_y >= query_low.y && leaf_y <= query_high.y)
        {
            result_idx.push_back(keypos_);
        }
        return;
    }
    else if (query_low.y <= ylow && query_high.y >= yhigh) // Query contains entire cell?
    {
        TraversalInorder(result_idx);
        return; // return entire subtree size
    }
    else if (query_high.y < ylow || query_low.y > yhigh) // no overlap
    {
        return;
    }
    else
    {
        float leaf_y = (*data_)[keypos_].y;

        // count left side      
        lchild_->RangeQuery(query_low, query_high, result_idx, ylow, leaf_y);
        // count right side         
        rchild_->RangeQuery(query_low, query_high, result_idx, leaf_y, yhigh);
    }
}

void RangeTree1D::TraversalInorder(std::vector<int>& result_idx)
{
    if (this->IsLeaf())
        result_idx.push_back(keypos_);
    else
    {
        lchild_->TraversalInorder(result_idx);
        rchild_->TraversalInorder(result_idx);
    }
}

bool RangeTree1D::IsLeaf()
{
    return (lchild_ == NULL && rchild_ == NULL);
}

/////////////////////////////////////////////
// class RangeTree2D
/////////////////////////////////////////////

RangeTree2D::RangeTree2D(const std::vector<FloatPoint>& in_data)
    : lchild_(NULL), rchild_(NULL), ytree_(NULL)
{
    data_.reset(new std::vector<FloatPoint>(in_data));
}

RangeTree2D::RangeTree2D(std::shared_ptr<std::vector<FloatPoint>>& data)
    : lchild_(NULL), rchild_(NULL), ytree_(NULL),
    data_(data)
{
}

RangeTree2D::~RangeTree2D()
{
    if (lchild_)
        delete lchild_;
    if (rchild_)
        delete rchild_;
    if (ytree_)
        delete ytree_;
}

bool RangeTree2D::BuildTree()
{
    std::vector<int> x_idx = SortIndex(*data_, xless);
    std::vector<int> y_idx = SortIndex(*data_, yless);

    return Build(x_idx, y_idx);
}

bool RangeTree2D::Build(std::vector<int>& x_idx, std::vector<int>& y_idx)
{
    size_t n = x_idx.size();
    if (n == 0)
        return false;

    size_t pos = !(n % 2) ? n / 2 - 1 : (n - 1) / 2;
    keypos_ = x_idx[pos];

    if (n == 1)
    {
        this->lchild_ = NULL;
        this->rchild_ = NULL;
    }
    else
    {
        std::vector<int> x_left, x_right;
        std::vector<int> y_left, y_right;
        std::vector<bool> in_left;

        x_left.assign(x_idx.begin(), x_idx.begin() + pos + 1);
        x_right.assign(x_idx.begin() + pos + 1, x_idx.end());

        // Mark down which index is in left child
        in_left.resize((*data_).size(), false);
        for (auto p : x_left)
        {
            in_left[p] = true;
        }

        // Build children's y order
        for (auto p : y_idx)
        {
            if (in_left[p])
                y_left.push_back(p);
            else
                y_right.push_back(p);
        }

        this->lchild_ = new RangeTree2D(data_);
        lchild_->Build(x_left, y_left);
        this->rchild_ = new RangeTree2D(data_);
        rchild_->Build(x_right, y_right);
    }

    // build y-tree.
    this->ytree_ = new RangeTree1D(data_);
    ytree_->Build(y_idx);

    return true;
}

void RangeTree2D::RangeQuery(FloatPoint &query_low, FloatPoint &query_high,
    std::vector<int>& result_idx)
{
    result_idx.clear();

    RangeQuery(query_low, query_high, result_idx, kXMin, kXMax);
}

void RangeTree2D::RangeQuery(FloatPoint &query_low, FloatPoint &query_high,
    std::vector<int>& result_idx, float xlow, float xhigh)
{
    if (this->IsLeaf()) // hit the leaf level?
    {
        float leaf_x = (*data_)[keypos_].x;
        float leaf_y = (*data_)[keypos_].y;

        // count if point in range
        if (leaf_x >= query_low.x && leaf_x <= query_high.x
            && leaf_y >= query_low.y && leaf_y <= query_high.y)
        {
            result_idx.push_back(keypos_);
        }
        return;
    }
    else if (query_low.x <= xlow && query_high.x >= xhigh)
    {   // Query’s x-range contains C
        // search auxiliary tree
        ytree_->RangeQuery(query_low, query_high, result_idx, kYMin, kYMax);
        return;
    }
    else if (query_high.x < xlow || query_low.x > xhigh) // no overlap
    {
        return;
    }
    else
    {
        float leaf_x = (*data_)[keypos_].x;

        // count left side
        lchild_->RangeQuery(query_low, query_high, result_idx, xlow, leaf_x);
        // count right side
        rchild_->RangeQuery(query_low, query_high, result_idx, leaf_x, xhigh);
    }
}

bool RangeTree2D::IsLeaf()
{
    return (lchild_ == NULL && rchild_ == NULL);
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容