Diskrétne geometrické štruktúry 2. Martin Florek florek@sccg.sk www.sccg.sk/~florek originál Martin Samuelčík, zmeny Martin Florek
Dec 30, 2015
Diskrétne geometrické štruktúry
2.
Martin Florekflorek@sccg.sk
www.sccg.sk/~florek
originál Martin Samuelčík, zmeny Martin Florek
Binárny prehľadávací strom
• Binárny prehľadávací strom – zložitosť na základe výšky stromu
• Potreba zabezpečiť čo najmenšiu výšku stromu
• Pre kompletný binárny strom s výškou h je počet vrcholov 2h – 1
• Cestu možeme skrátiť až na lg(n+1)• Potreba vyváženosti v každom vrchole
AVL stromy
• Adelson-Velskii a Landis• AVL strom je samovyvažujúci sa BPS• pre každý jeho vrchol v platí:
– buď v je list– alebo v má jedného syna, ktorý je list– alebo v má dvoch synov. Ak ľavý podstrom vrchola
v má výšku h1 a pravý h2, potom platí:h1 – h2 1
– b(v) = h1 – h2
• lg(n+1) h 1,44*lg(n+2)
Vkladanie prvku do AVL stromu
• Najprv Insert pre BPS• V niektorých vrcholoch môže vzniknúť
nevyváženosť• Vrchol x treba vyvažovať práve vtedy, keď
platia nasledujúce dve podmienky:– b(x) = 1 a nový vrchol je pridaný doľava od x, – b(x) = -1 a nový vrchol je pridaný doprava od x,– pre y, ktorý leží na ceste od x ku pridávanému
vrcholu platí: b(y) = 0
Vyvažovanie
• Podstrom s nevyváženým vrcholom treba preskupiť aby nastala vyváženosť
• Treba zachovať pravidlá BPS• Treba zachovať výšku podstromu, aby sa
nemuseli vyvažovať ostatne vrcholy• Viaceré konfigurácie - rotácie
AVL_INSERT(T, v){
x = T->root;if (T->root == NULL) {T->root = v; v->b = 0;}else{
INSERT (T->root, v);MODIFY (x, v);if (x->b == 2){
if (x->left->b == 1) vyvažuj podľa Aif (x->left->b == -1) vyvažuj podľa B
}if (x->b == -2){ Symetricky ku (b(x) == 2);}
}}
struct AVLNode{
int key;AVLNode* left;AVLNode* right;AVLNode* parent;int b;void* data;
}
struct AVLTree{
AVLNode* root;}
MODIFY (u, v){
if (v->key < u->key)if (u->left != NULL) {
u->b = u->b + 1;MODIFY (u->left, v);
}if (v->key > u->key)
if (u->right != NULL) {
u->b = u->b – 1;MODIFY (u->right, v);
}}
INSERT (u, v){
if (v->key < u->key)if (u->left == NULL) {u->left = v; if (u->b != 0) x = u;}else{
if (u->b != 0) x = u; INSERT (u->left, v);}
if (v->key > u->key)if (u->right == NULL) { u->right = v; if (u->b != 0) x = u;}else{
if (u->b != 0) x = u; INSERT (u->right, v);}
}
AVL – algoritmy
Rotácie
LL rotation
RR rotation
Rotácie 2
LR rotation
RL rotation
Vymazanie vrcholu z AVL
• Rozšírenie DELETE pre BPS:• 1) v má najviac 1 syna:
• vrchol v vynecháme ako pri DELETE pre BPS• x = vparent;• BALANCE (x, v);• delete v;
• 2) v má dvoch synov: • nájdeme maximum v ľavom podstrome vrchola v
(MAX)• vymeníme v a MAX• postupujeme podľa 1)
Balance
BALANCE (x, v){
if (x != NULL){
if ((v->key < x->key) && (x->b 0)){
x->b = x->b – 1;if (x->b == 0) BALANCE (x->parent, v);
}if (v->key > x->key) and (x->b 0){
x->b = x->b + 1;if (x->b == 0) BALANCE (x->parent, v);
}if (v->key > x->key) and (x->b == 1) situácia A alebo Bif (v->key < x->key) and (x->b == -1) situácia symetr. ku A alebo Bif (vyvažovanie A resp. B && x->parent nevyváženosť) BALANCE (xparent, v);
}}
Rotácie 3
Zložitosť pre AVL stromy
• Daná výškou stromu• Asymptotická zložitosť operácií: O(log n)• Maximálny počet prechodov: 1.44 * lg(n)• Insert: možná jedna-dve rotácie, priemerne 1
rotácia na 2 vloženia• Delete: možnosť veľa rotácií pre jedno
vymazanie, priemerne 1 rotácia na 5 vymazaní
Červeno-čierne stromy
• Iné pravidlá pre vyváženie:1. Každý vrchol je čierny alebo červený2. Koreň stromu je čierny3. Všetky listy stromu sú čierne4. Synovia červeného vrcholu sú čierny5. Každá cesta z vrcholu v do nejakého listu má
rovnaký počet čiernych vrcholov
Vlastnosti
• bh(n) – počet čiernych vrcholov na ceste z vrchola n do listu
• R-B strom má výšku maximálne 2.lg(n+1)• Dĺžka najdlhšej cesty z koreňa do listu nie je
väčšia ako dvojnásobná dĺžka najkratšej cesty z koreňa do listu
• Na jednej ceste z vrcholu do listu nemôže byť viac červených vrcholov ako čiernych
Vkladanie
• BPS vkladanie• Vlož vrchol ako červený• Postupuj od vloženého vrcholu až do koreňa
hľadaj porušenie pravidla 3, 4 a 5• Ak je porušené pravidlo prefarbuj alebo rotuj
v okolí daného vrchola
Vkladanie 2RB_INSERT (T, x){
BPS_INSERT(T, x);x->color = RED;while (x != T->root && x->parent->color == RED){
if (x->parent == x->parent->parent->left){
Y = x->parent->parent->right;if (y->color == RED){
x->parent->color = BLACK;y->color = BLACK;x->parent->parent = RED;x = x->parent->parent;
}else{
if (x == x->parent->right){ x = x->parent; LeftRotate(x);}x->parent->color = BLACK;x->parent->parent->color = RED;RightRotate(x->parent->parent);
}}else{ // symetricky, vymenit left a right}
}}
Prípad 1
Prípad 2
Prípad 3
Vymazanie vrcholu z R-B
• Mazanie ako pri BPS• Ak zmazaný vrchol bol červený, nič sa nedeje• Ak je vrchol čierny, treba urobiť spätný
prechod od mazaného vrcholu do koreňa a opravovať podmienky
• Použitie rotácií a prefarbovania
B-stromy
• Každý vrchol obsahuje aspoň n synov• Každý vrchol obsahuje najviac 2n vrcholov• Všetky listy sú na jednej úrovni• V každom vrchole je počet kľúčov o 1 menší ako
počet potomkov• n – rád stromu• Výška stromu – O(lognN)• Netreba tak často vyvažovať• Plytvá miestom – vhodné pre velké bloky dát
B-stromy 2
• Vkladanie – kontrola na prekročenie limitu 2.n
• Mazanie – kontrola na počet potomkov aspoň n
• Náprava – rozdeľovanie, spájanie kľúčov, rotácie
Halda
• Stromová štruktúra• Ak vrchol B je potomok vrcholu A, tak key(A)
key(B) (key(A) key(B))• Vytvorenie v O(n)• Použitie:
– Triedenie– Prehľadávanie utriedených množín– Grafové algoritmy– Prioritná fronta
Zásobník
• Princíp Last In First Out (LIFO), posledný uložený prvok sa vyberie ako prvý
• Operácie (push, pop, peek, size, …)• Použitie:
– spracovanie výrazov– manažment pämate– skladanie transformácií
Fronta
• Princíp First In First Out (FIFO)• Prvky sa vkladajú na jednom konci, vyberajú
na druhom• Vyberá sa vždy „najstarší“ prvok vo fronte• Prioritná fronta:
– Pridaj prvok s definovanou prioritou– Vyber prvok s najvyššou prioritou
Oknové a bodové požiadavky
• Či sa bod nachádza v danej množine• Všetky body v danej množine• Všetky objekty v danom okne• Priesečníky okien• Požiadavka:
– Rozmer priestoru– Prislušná dvojica objektov– Typ požiadavky
Intervalové stromy
• Binárny strom pre požiadavku interval/bod• Vstup: množina S uzavretých
jednorozmerných intervalov• Požiadavka: reálna hodnota xq
• Výstup: všetky intervaly I S také, že xq I
• S = {[li, ri] pre i = 1, …, n}
Vrcholy stromu
• Xmed – medián, ktorým bola rozdelená množina intervalov v tomto vrchole
• Lmed- usporiadaná množina ľavých koncových bodov intervalov, ktoré obsahovali Xmed
• Rmed- usporiadaná množina pravých koncových bodov intervalov, ktoré obsahovali Xmed
• Smerníky na dvoch synovstruct IntervalTreeNode{
float xmed;vector<float> Lmed;vector<float> Rmed;IntervalTreeNode * left;IntervalTreeNode * right;
}
struct IntervalTree{ IntervalTreeNode* root;}
Vytvorenie stromu• Pre n intervalov,
intervalový strom sa dá vytvoriť v čase O(n.log n) a zaberie O(n) pamäte
IntervalTreeNodeConstruct(S){
if (S == 0) return NULL;v = new IntervalTreeNode;v->xmed = Median(S);Smed = HitSegments(v->xmed, S); L = LeftSegments(v->xmed, S);R = RightSegments(v->xmed, S);v->Lmed = SortLeftEndPoints(Smed);v->Rmed = SortRightEndPoints(Smed) v->left = IntervalTreeNodeConstruct(L);v->right = IntervalTreeNodeConstruct(R);return v;
}
IntervalTreeConstruct(S){
T = new IntervalTree;T = IntervalTreeNodeConstruct(S);return T;
}
Vyhľadanie
• Pre množinu n intervalov, požiadavka na vyhľadanie vráti k intervalov v čase O(k + log n)
IntervalStabbing(v, xq){
D = new List;if (xq < v->xmed){
L = v->Lmed;F = L.first;while (F != NULL && F < xq){
D.insert(Seg(F));F = L.next;
}D1 = IntervalStabbing(v->left, xq);D.add(D1);
}else{
R = v->Rmed;F = R.first;while (F != NULL && F > xq){
D.insert(Seg(F));F = R.next;
}D2 = IntervalStabbing(v->right, xq);D.add(D2);
}
return D;}
Segmentové (úsečkové) stromy
• Vyhľadanie všetkých úsečiek z danej množiny, ktoré sa pretínajú s danou zvislou priamkou
• Vstup: množina úsečiek S v rovine• Požiadavka: zvislá priamka l• Výstup: všetky úsečky s S, ktoré pretínajú l• S = {s1, s2, …, sn}
Prehľadávací strom
• Usporiadame x-ové súradnice koncových bodov úsečiek, E = {e1, e2, …, e2n}
• Rozdeľ E na intervaly [-∞,e1], …, [e2n-1, e2n], [e2n, ∞]
• Základné intervaly budú listy prehľadávacieho stromu SearchTreeNodeConstruct (S)
{if (|S| == 0) return NULL;v = new SegmentTreeNode;n = |S|;m = n / 2;(L, R) = Split(S, m);v->key = S.get(m);v->istart = S.get(1);v->iend = S.get(n);v->left = SearchTreeNodeConstruct(L);v->right = SearchTreeNodeConstruct(R);return v;
}
struct SegmentTreeNode{
float key;float istart;float iend;List L;IntervalTreeNode* left;IntervalTreeNode* right;
}
Segmentový strom
• Máme malé intervaly uložené v stromovej štruktúre
• Naplníme tento strom príslušnosťou ku úsečkám tak, aby každá úsečka bola pokrytá čo najmenším počtom intervalov (vrcholov) prehľadávacieho stromu
• Vytvorenie seg. stromu má časovú zložitosť O(n.logn), strom využije O(n.logn) pamäte
Vytvorenie segmentového stromuInsertSegment(v, s){
if (v == NULL) return;if ([v->istart, v->iend] s == 0) return;if ([v->istart, v->iend] s){
v->l.add(s);}else{
InsertSegment(v->left, s);InsertSegment(v->right, s);
}}
BuildSegmentTree(S){
Sx = S.SortX();Sx.ExtendInfinity();New T = new SegementTree;T->root = SearchTreeNodeConstruct(Sx);while (S.first != 0){
InsertSegment(T->root, S.first);
S.deleteFirst();}
}
struct SegmentTree{ SegmentTreeNode* root;}
Vyhľadanie
• Pre n úsečiek v rovine, nájdenie všetkých úsečiek ktoré pretínajú danú zvislú priamku má časovú náročnosť O(k + log n), kde k je počet nájdených úsečiek
StabbingQuery(v, l){
List L;If (v != NULL && l [v->istart, v->iend]){
L = v.L;L1 = StabbingQuery(v->left, l);L2 = StabbingQuery(v->right, l);L.add(L1);L.add(L2);return L;
}}
Viacrozmerné segmentové stromy• Vstup: množina d-
rozmerných obdĺžnikov S rovnobežných so súradnicovými osami
• Požiadavka: bod q z Rd
• Výstup: množina boxov z S ktoré obsahujú bod q
• V každom vrchole d-rozmerného stromu sa môže nachádzať d-1 rozmerný strom
MLSegmentTree(B, d) {
S = B.FirstSegmentsExtract;T = SegmentTreeConstruct(S);T.dim = d;if (d > 1){
N = T.GetAllNodes;while (|N| != 0) {
u = N.First;N.DeleteFirst;L = u->L;List B;while (|L| != 0){
s = L.First;L.DeleteFirst;B.add(s.Box(d − 1));
}u->tree = MLSegmentTree(B, d − 1);
}}return T;
}
Viacrozmerné segmentové stromy 2MLSegmentTreeQuery(T, q, d) {
if (d == 1) {
L = StabbingQuery(T, q);return L;
}else {
List A;L = SearchTreeQuery(T, q.First);while (|L| != 0) {
t = (L.First)->tree;B = MLSegmentTreeQuery(t, q.Rest, d − 1);A.ListAdd(B);L.DeleteFirst;
}return A;
}}
Čas zostrojenia: O(n.logdn)Pamäť: O(n.logdn)Požiadavka: O(k + logdn)
Range stromy
• Vstup: množina bodov S v Rd
• Požiadavka: obdĺžnik B z Rd rovnobežný so súradnicovými osami
• Výstup: Množina bodov z S, ktoré patria obdĺžniku B
• Podobná metóda ako pri segmentových stromoch• Vytvorenie prehľadávacieho stromu na základe
súradníc bodov• Väčšinou d ≥ 2
Range stromy 2
• Pre jednorozmerný prípad – hľadanie bodov vo vnútri intervalu
• Vytvorenie prehľadávacieho stromu
Range stromy 3• Vrchol d-rozmerného range stromu môže obsahovať
d-1 rozmerný range stromRangeTreeConstruct(S, d) {
Sf = S.FirstCoordElements;Sf.Sort;T = SearchTree(Sf);T->dim = d;if (d > 1){
N = T->GetAllNodes;while (|N| != 0){
u = N.First; N.DeleteFirst;L = u->GetAllPoints;List D;while (|L| != 0) {
x = L.First; L.DeleteFirst;D.add(x.Point(d − 1));
}u->tree = RangeTreeConstruct(D, d − 1);
}}return T;
}
Zložitosť
• d-rozmerný range strom pre množinu n bodov v Rd môže byť vytvorený v čase O(n.log(d−1)n) a spotrebuje O(n.log(d−1)n) pamäte
• Požiadavka na zistenie bodov vnútri d-rozmerného boxu má časovú náročnosť O(k + logdn)
AABB/AABB
• Vstup: množina S 2D intervalov (obdĺžnikov)• Požiadavka: 2D interval B• Výstup: všetky AABB z S ktoré majú prienik s B• Tri možnosti prieniku:
– B je vnútri Bi
– Roh Bi leží v B– Strana Bi pretína B a žiadny koncový bod Bi nie je v
B
AABB/AABB 2
• Prípad 1. – 2D segmentový strom. Hľadáme do ktorých boxov Bi z S padnú štyri rohy B– čas O(k1 + log2n) a pamäť O(n + log2n)
• Prípad 2. – Range strom v 2D. Hľadáme rohy boxov Bi ktoré padnú do obdĺžnika B– čas O(k2 + log2n) a pamäť O(n.logn).
• Prípad 3. – Nová požiadavka:– Vstup: Množina horizontálnych čiar v 2D– Požiadavka: Vertikálna čiara s v 2D– Output: Všetky úsečky pretínajúce s
AABB/AABB – Prípad 3
• V smere x hľadanie častí s priesečníkom, v smere y časti patriace do intervalu
• Kombinácia intervalového a range stromu• Najprv vytvoríme intervalový strom• Lmed a Rmed nahradíme prislušnými 2D range
stromami• Čas O(k3 + log2n), pamäť O(n.logn)
Rozšírenie
• Nielen pre geometrické dáta• Vyhľadávanie v d-rozmerných dátach• Podľa požiadaviek, hľadanie dát v danom
intervale, hľadanie približných dát• Porovnávanie objektov
koniec (-:florek@sccg.sk