Kd-tree

Versiunea actuală a paginii nu a fost încă examinată de colaboratori experimentați și poate diferi semnificativ de versiunea revizuită pe 23 iulie 2021; verificările necesită 2 modificări .
Arborele K-dimensional
Tip de Arborele multidimensional Arborele de căutare binar
Anul inventiei 1975
Autor Jon Bentley
Complexitatea în simbolurile O
In medie În cel mai rău caz
Consumul de memorie O( n ) O( n )
Căutare O( login ) O( n )
Introduce O( login ) O( n )
Îndepărtarea O( login ) O( n )

Un k -d-tree ( eng.  kd tree , prescurtare pentru arbore k-dimensional ) este o structură de date partiționată în spațiu pentru ordonarea punctelor într-un spațiu k - dimensional. k -d-arborele sunt utilizați pentru unele aplicații, cum ar fi căutarea multidimensională cu spațiu de taste (căutare în interval și căutare în cel mai apropiat vecin ). k -d-trees sunt un tip special de arbori binari de căutare .

Descriere matematică

Un arbore K-dimensional este un arbore de căutare dezechilibrat pentru stocarea punctelor din . Oferă o capacitate asemănătoare arborelui R de a căuta într-un interval dat de taste. În detrimentul simplității interogărilor, cerințele de memorie în loc de .

Există arbori kd omogene și neomogene. În arborii kd omogene, fiecare nod stochează o înregistrare . În varianta eterogenă, nodurile interne conțin doar chei, frunzele conțin link-uri către înregistrări.

Într-un arbore kd neomogen cu un hiperplan -dimensional paralel cu axa în punctul . Pentru rădăcină, trebuie să împărțiți punctele prin hiperplan în două seturi de puncte cât mai mari posibil și să scrieți la rădăcină, în stânga acesteia, toate punctele pentru care sunt stocate , la dreapta, cele pentru care . Pentru subarborele din stânga trebuie să împărțiți din nou punctele într-un nou „plan divizat” și este stocat în nodul intern. În stânga acestuia, toate punctele pentru care . Aceasta continuă recursiv pe toate spațiile. Apoi totul începe din nou din primul spațiu până când fiecare punct poate fi identificat clar prin hiperplan.

arborele kd poate fi construit în . O căutare în intervalul poate fi efectuată în , prin care indică dimensiunea răspunsului. Necesarul de memorie pentru arborele în sine este limitat .

Operații pe k -d-arbori

Structura

Structura arborescentă descrisă în C++ :

amprenta constex N = 10 ; _ // numărul de spații de taste struct Item { // item structure int key [ N ]; // matrice de chei care definesc elementul char * info ; // informații despre element }; struct Node { // structura nodului arborescent Item i ; // element Node * stânga ; // subarborele stânga Nod * dreapta ; // subarborele din dreapta }

Structura arborelui poate varia în funcție de detaliile implementării algoritmului . De exemplu, un nod poate conține mai degrabă o matrice decât un singur element, ceea ce îmbunătățește eficiența căutării.

Analiza Căutării Elementelor

Evident, numărul minim de elemente vizualizate este , iar numărul maxim de elemente vizualizate este , unde  este înălțimea arborelui. Rămâne de calculat numărul mediu de articole vizualizate .

 este elementul dat.

Să luăm în considerare cazul . Elementele găsite pot fi:

și așa mai departe pentru fiecare spațiu de taste. În acest caz, lungimea medie a căutării într-un spațiu este:

.

Valoarea medie se calculează cu formula:

Rămâne de găsit probabilitatea . Este egal cu , unde  este numărul de cazuri, când și  este numărul total de cazuri. Nu este greu de ghicit ce .

Inlocuim aceasta in formula pentru valoarea medie:

,

adică unde  este înălțimea copacului.

Dacă mergem de la înălțimea arborelui la numărul de elemente, atunci:

, unde  este numărul de elemente din nod.

Din aceasta putem concluziona că cu cât vor fi conținute mai multe elemente în nod, cu atât căutarea arborelui va fi mai rapidă, deoarece înălțimea arborelui va rămâne minimă, dar nu ar trebui să stocați un număr mare de elemente în nod, deoarece cu această metodă întregul arbore poate degenera într-o matrice sau listă normală.

Adăugarea elementelor

Adăugarea elementelor are loc exact în același mod ca într-un arbore de căutare binar normal , cu singura diferență că fiecare nivel al arborelui va fi determinat și de spațiul căruia îi aparține.

Algoritm de progresie a arborelui:

pentru ( int i = 0 ; arbore ; i ++ ) // i este numărul spațiului dacă ( arbore -> x [ i ] < arbore -> t ) // t este arborele median = arbore -> stânga ; // trece la subarborele din stânga altfel copac = copac -> dreapta ; // se deplasează în subarborele din dreapta

Adăugarea se efectuează după , unde  este înălțimea arborelui.

Eliminarea elementelor

La ștergerea elementelor arborelui, pot apărea mai multe situații:

  • Ștergerea unei frunze de copac este o ștergere destul de simplă, atunci când un nod este șters și indicatorul nodului strămoș este pur și simplu resetat la zero.
  • Eliminarea unui nod de arbore (nu a unei frunze) este o procedură foarte complicată, în care trebuie să reconstruiți întregul subarboresc pentru acest nod.

Uneori, procesul de ștergere a unui nod este rezolvat prin modificarea arborelui kd. De exemplu, dacă nodul nostru conține o matrice de elemente, atunci când întregul tablou este șters, nodul arborelui rămâne, dar elemente noi nu mai sunt scrise acolo.

Găsirea unei game de elemente

Căutarea se bazează pe coborârea normală a arborelui, unde fiecare nod este verificat pentru un interval. Dacă medianele unui nod sunt mai mici sau mai mari decât un interval dat într-un spațiu dat, atunci traversarea merge mai departe de-a lungul uneia dintre ramurile arborelui. Dacă mediana nodului este complet în intervalul dat, atunci ambii subarbori trebuie vizitați.

Algoritm Z - nodul arborelui [( x_0_min , x_1_min , x_2_min ,..., x_n_min ),( x_0_max , x_1_max , x_2_max ,..., x_n_max )] - interval specificat Matrice de funcții ( Nodul *& Z ){ Dacă ([ x_0_min , x_1_min , x_2_min ,..., x_n_min ] < Z ){ Z = Z -> stânga ; // subarborele stânga } altfel Dacă ([ x_0_max , x_1_max , x_2_max ,..., x_n_max ] > Z ){ Z = Z -> dreapta ; // subarborele din dreapta } Altfel { // vizualizați ambii subarbori din Array ( Z -> dreapta ); // rulează funcția pentru subarborele din dreapta Z = Z -> stânga ; // vezi subarborele din stânga } } Analiză

Evident, numărul minim de elemente vizualizate este , unde  este înălțimea arborelui. De asemenea, este evident că numărul maxim de elemente vizualizate este , adică vizualizarea tuturor elementelor arborelui. Rămâne de calculat numărul mediu de articole vizualizate .

 - interval dat.

Articolul original despre kd-trees oferă următoarea caracteristică: pentru un interval fix.

Dacă mergem de la înălțimea arborelui la numărul de elemente, atunci acesta va fi:

Găsirea celui mai apropiat vecin

Căutarea celui mai apropiat element este împărțită în două subsarcini: determinarea celui mai apropiat element posibil și găsirea celor mai apropiate elemente dintr-un interval dat.

Dat un copac . Coborâm copacul la frunzele sale în funcție de condiție și determinăm cel mai apropiat element probabil după condiție . După aceea, de la rădăcina arborelui, se lansează algoritmul pentru găsirea celui mai apropiat element din intervalul dat, care este determinat de raza .

Raza de căutare este ajustată atunci când este găsit un element mai apropiat.

Algoritm Z este rădăcina copacului Listă - o listă pentru cele mai apropiate elemente găsite [ x_0 , x_1 , x_2 ..., x_n ] - coordonatele tuturor dimensiunilor elementului nostru , pentru care cel mai apropiat Len - lungime minimă COPII - numărul maxim de copii pentru fiecare element Funcția Maybe_Near ( Node *& Z ) { // caută cel mai apropiat element posibil în timp ce ( Z ) { pentru ( i = 0 ; i < N ; i ++ ) { // verifica elementele din nodul len_cur = sqrt (( x_0 - x [ i ] _0 ) ^ 2 + ( x_1 - x [ i ] _1 ) ^ 2 + . .. + ( x_n - x [ i ] _n ) ^ 2 ); // lungimea elementului curent if ( Len > lungimea elementului curent ) { Len = len_cur ; // setează o nouă lungime Delete ( List ); // ștergerea listei Add ( List ); // adaugă un nou element la listă } else if ( lungimile sunt egale ) { Adăugați ( Lista ); // adaugă un nou element la listă } dacă (( x_0 == x [ i ] _0 ) && ( x_1 == x [ i ] _1 ) && ... && ( x_n == x [ i ] _n )) { întoarcere 1 ; } } dacă ([ x_0 , x_1 , x_2 ..., x_n ] < Z ) Z = Z -> stânga ; // subarborele stânga dacă ([ x_0 , x_1 , x_2 ..., x_n ] > Z ) Z = Z -> dreapta ; // subarborele din dreapta } } Funcția Aproape ( Nod *& Z ) { // caută recursiv cel mai apropiat element din intervalul dat dacă ( ! Z ) { returneaza Lista ; } len_cur = sqrt (( x_0 - x [ i ] _0 ) ^ 2 + ( x_1 - x [ i ] _1 ) ^ 2 + ... + ( x_n - x [ i ] _n ) ^ 2 ); // distanta de la punctul nostru la cel curent if ( len_cur < Len ) { // a gasit o lungime mai mica decat minima Len = len_cur ; // setează o nouă lungime minimă Delete ( List ); // ștergerea listei - la urma urmei, toate elementele găsite până acum sunt mai departe decât cea actuală Adaugă ( Listă , Z ); // adaugă elementul curent la listă } else if ( len_cur == Len ) { // lungimea este egală cu Adăugarea minimă ( List , Z ); // adaugă doar un element nou în listă } pentru ( i = 0 ; i < COPII ; i ++ ) { // faceți la fel pentru toți copiii Aproape ( Z -> copii [ i ]); // vezi toate subarborele } } Analiză

Evident, numărul minim de elemente vizualizate este , unde h este înălțimea arborelui. De asemenea, este evident că numărul maxim de elemente vizualizate este , adică vizualizarea tuturor nodurilor. Rămâne de calculat numărul mediu de articole vizualizate.

 este un element dat față de care doriți să găsiți cel mai apropiat. Această sarcină este împărțită în două subsarcini: găsirea celui mai apropiat element dintr-un nod și găsirea celui mai apropiat element dintr-un interval dat. Pentru a rezolva prima subproblemă, este necesară o coborâre de-a lungul copacului, adică .

Pentru a doua subsarcină, așa cum am calculat deja, căutarea elementelor dintr-un interval dat durează . Pentru a găsi media, adăugați pur și simplu aceste două valori:

.

Vezi și

Note

Link -uri