KDツリー(K次元データ構造)

KDツリーは、アルゴリズムの近くにあるK

  KDツリーは、ツリーを維持するために、k次元の要素であると言い換える手段におけるk次元の略語、すなわち、k次元の木であり、ツリーのノードは、K個の成分を有します。k次元のバイナリ検索ツリーは、kd木です。

  KDツリーの概念を初めて目

実施例(図ネットワーク)

K == KDツリーモデル3

  ツリーの下に編成原理が最初に実行されます。0によって順序付けタプルのそれぞれ、ツリーの第n層、3つの項目は太字で示されているn個の%(0は最初の数、第二の数が1である、第3の数は2である)、およびバイナリ検索ツリーキー値があるようにツリーが太字で示され、例えば、各ノードのルートノードの左の部分木における最初のアイテムが少ない第1ルートノードより、ノード右部分木であります最初の項目は、最初のルートノードよりも大きく、サブツリーので。

  このようなツリーのために、ノードはタプル与え、容易に検索し、そしてまず、第1のルートノードとを比較する、未満、右、第2の比較器の第二の層などよりも大きいを残しました。

  そこで、我々は実績の原則ことを知っているが、この貢献は何のためにあるのですか?

1次元モデルK == KDツリー1を参照してください、私たちはになります座標軸を投影。

  このように、モデルは、二分探索木、私たちは、あなたが検索を実行するために二分探索木のBSTの原理を使用することができるポイント値を見つけたいです。

  だから、今、私たちは2次元の行が続くポイントでオリジナルの分割は、オープン分割し、それを使用することですので、この一次元、二次元へを展開したいです。

  セグメンテーション図中点の軸に直線垂直を用い

まず:イエローポイント

第二:赤い点

第三:グリーンポイント

第四:ブルーポイント

アルゴリズムの終わり。

このように、我々は、アートワークスタイルの複数の部分に分けられますが、K == 2は、検索二次元空間のBST二分探索木を利用できることを保証することができたことになります。

これが分割される理由を理解することができ、前に同様に、K == 3、私たちは例が与えられた表示されます。

貢献

  貢献は、ここで二分探索木アプローチの考えに基づいているCDQのパーティションに似ています。

各要素は、我々はそれの分割左右のサブツリーの標準コンポーネントとして行かなければならないk個の要素を持っているので、質問は、ありますか? 
自分の順番はもちろん可能の各コンポーネントを分割します。 
ベターたびは、コンポーネントの最大のスパンが分かれていることです。

どのように理解するには? 
私たちは今、nは、2次元の点(x、y)とK == 2は、我々はkd木にそれを構築する必要があることを前提としています。

尺度として順番に各成分が下記されている場合: 
端に長方形、正方形この我々最初のカットバックで今これらの点、この分割されたXのビットに相当し、左の点は、左サブツリーの右に入りました右部分木へのポイント。 
左右それぞれ、と我々は左と右のサブツリーにそれぞれ上下点の両側に、背側方に切断するための矩形が次にあります。 
などなど......

各選択されたスパンが分割される各矩形は長いの水平方向または垂直方向の長さの長さであるかを確認するコンポーネント分割されています。その後、我々は脳を作ることができます。

今別の問題、そして我々は我々かどうか、それを分割先のノードとして、分割次元を決定し、すべての時間の後?(どのような位置に長方形の中に実際にカットバックと同等?) 
答えは明白であるように、我々は確かに左右のサブツリーノードことを願って近い、より良い、私たちはライン上の中央値は、サブツリーの左右の位置を分けます。

void build(int rt, int l, int r)
{
    if(l > r) return;
    op = 0; key[rt] = 0;
    for(int i=0; i<K; i++)
    {
        double ave = 0.;
        var[i] = 0.;
        for(int j=l; j<=r; j++) ave += a[j].d[i];
        ave /= (r - l + 1.);
        for(int j=l; j<=r; j++) var[i] += (ave - a[j].d[i]) * (ave - a[j].d[i]);
        var[i] /= (r - l + 1.);
        if(var[i] > var[key[rt]])
        {
            key[rt] = i;
            op = i;
        }
    }
    int mid = HalF;
    nth_element(a + l, a + mid, a + r + 1, cmp);
    tree[rt] = a[mid];
    build(rt << 1, l, mid - 1); build(Rson);
}

したがって、私の貢献は、このようなコードです。

どのSTLを使用しています。

C ++ nth_element(STL nth_element)ソートアルゴリズム

  その適用範囲は、第一及び第三のパラメータによって指定されます。(中間パラメータなど)は、第2のパラメータは、 n番目の要素を指すイテレータです。要素が完全にこの範囲内で順序付けられている場合、nth_dement()が実行され、n番目の要素が位置に配置されているもたらします。この範囲内で、n番目の要素の前の要素は、n番目の要素、及びそれよりも大きいであろう次の各要素よりも小さいです。結果を生成するために、「<」演算子を使用して、デフォルトのアルゴリズム。

これは一例であり、(要素のセット:22、7、93、45、19、56、88、12、8、7、15、10)

お問い合わせ

  問題のkd木は、多くの場合、処理するのに使用されるクエリのk次元空間にポイント最も近い点を。 
アプローチは、最も近い距離の各点における電流を更新するかどうかを決定するために、ルートノードから開始することです。そして、左または右のサブツリーサブツリーのクエリ、対応するサブツリーを入力しますが、最も近い距離を更新し続けるかどうかを決定します。

しかし、問題があり、ポイントは、我々は時間のバックトラックの別の区間内に再帰クエリを判断または必要する必要があるので、クエリ間隔は、最も近い点を有することも可能であるということではありません。 
この条件は、2つの大きなセクションに分割対象点超平面の間の距離よりも至近によって維持されている分析、または他の言葉では、目標点の球の中心、分割された他の半径を有する現在の最小距離超球であります一部の交差。

クエリ最良の場合はO(LOGN)最悪の場合はO(n)があります

void query(int rt, int l, int r)
{
    if(l > r) return;
    int mid = HalF;
    ll dist = dis(q, tree[rt]);
    if(q.id ^ tree[rt].id)
    {
        if(dist < ans)
        {
            ans = dist;
            point = tree[rt];
        }
    }
    int k_key = key[rt];
    ll ra = (q.d[k_key] - tree[rt].d[k_key]) * (q.d[k_key] - tree[rt].d[k_key]);
    if(q.d[k_key] < tree[rt].d[k_key])
    {
        query(rt << 1, l, mid - 1);
        if(ra <= ans) query(Rson);
    }
    else
    {
        query(Rson);
        if(ra <= ans) query(rt << 1, l, mid - 1);
    }
}

正方形テンプレートタイトルは、ユークリッド距離の各点で2次元平面に最も近い点を求めます

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f3f3f3f3f
#define eps 1e-8
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
#define MAX_3(a, b, c) max(a, max(b, c))
#define Rabc(x) x > 0 ? x : -x
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int K = 2, maxN = 1e5 + 7;
int N;
struct node
{
    ll d[K]; int id;
    node(ll a=0, ll b=0, int c=0):d{a, b}, id(c) {}
    void In() { scanf("%lld%lld", &d[0], &d[1]); }
} tree[maxN << 2], a[maxN], b[maxN];
int op;
inline bool cmp(node e1, node e2) { return e1.d[op] < e2.d[op]; }
node q, point;
ll ans;
int key[maxN << 2];
double var[maxN << 2];
ll dis(node a, node b)
{
    ll sum = 0;
    for(int i=0; i<K; i++) sum += (a.d[i] - b.d[i]) * (a.d[i] - b.d[i]);
    return sum;
}
void build(int rt, int l, int r)
{
    if(l > r) return;
    op = 0; key[rt] = 0;
    for(int i=0; i<K; i++)
    {
        double ave = 0.;
        var[i] = 0.;
        for(int j=l; j<=r; j++) ave += a[j].d[i];
        ave /= (r - l + 1.);
        for(int j=l; j<=r; j++) var[i] += (ave - a[j].d[i]) * (ave - a[j].d[i]);
        var[i] /= (r - l + 1.);
        if(var[i] > var[key[rt]])
        {
            key[rt] = i;
            op = i;
        }
    }
    int mid = HalF;
    nth_element(a + l, a + mid, a + r + 1, cmp);
    tree[rt] = a[mid];
    build(rt << 1, l, mid - 1); build(Rson);
}
void query(int rt, int l, int r)
{
    if(l > r) return;
    int mid = HalF;
    ll dist = dis(q, tree[rt]);
    if(q.id ^ tree[rt].id)
    {
        if(dist < ans)
        {
            ans = dist;
            point = tree[rt];
        }
    }
    int k_key = key[rt];
    ll ra = (q.d[k_key] - tree[rt].d[k_key]) * (q.d[k_key] - tree[rt].d[k_key]);
    if(q.d[k_key] < tree[rt].d[k_key])
    {
        query(rt << 1, l, mid - 1);
        if(ra <= ans) query(Rson);
    }
    else
    {
        query(Rson);
        if(ra <= ans) query(rt << 1, l, mid - 1);
    }
}
int main()
{
    int T; scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &N);
        for(int i=1; i<=N; i++)
        {
            a[i].In();
            a[i].id = i;
            b[i] = a[i];
        }
        build(1, 1, N);
        for(int i=1; i<=N; i++)
        {
            q = b[i];
            ans = INF;
            query(1, 1, N);
            printf("%lld\n", ans);
        }
    }
    return 0;
}

 

公開された860元の記事 ウォンの賞賛1026 ビュー11万+

おすすめ

転載: blog.csdn.net/qq_41730082/article/details/105044095