\(\newcommand{\footnotename}{footnote}\)
\(\def \LWRfootnote {1}\)
\(\newcommand {\footnote }[2][\LWRfootnote ]{{}^{\mathrm {#1}}}\)
\(\newcommand {\footnotemark }[1][\LWRfootnote ]{{}^{\mathrm {#1}}}\)
\(\newcommand \ensuremath [1]{#1}\)
\(\newcommand {\LWRframebox }[2][]{\fbox {#2}} \newcommand {\framebox }[1][]{\LWRframebox } \)
\(\newcommand {\setlength }[2]{}\)
\(\newcommand {\addtolength }[2]{}\)
\(\newcommand {\setcounter }[2]{}\)
\(\newcommand {\addtocounter }[2]{}\)
\(\newcommand {\cline }[1]{}\)
\(\newcommand {\directlua }[1]{\text {(directlua)}}\)
\(\newcommand {\luatexdirectlua }[1]{\text {(directlua)}}\)
\(\newcommand {\protect }{}\)
\(\def \LWRabsorbnumber #1 {}\)
\(\def \LWRabsorbquotenumber "#1 {}\)
\(\def \mathchar {\ifnextchar "\LWRabsorbquotenumber \LWRabsorbnumber }\)
\(\def \mathcode #1={\mathchar }\)
\(\let \delcode \mathcode \)
\(\let \delimiter \mathchar \)
\(\let \LWRref \ref \)
\(\renewcommand {\ref }{\ifstar \LWRref \LWRref }\)
\(\newcommand {\intertext }[1]{\text {#1}\notag \\}\)
\(\newcommand {\mathllap }[2][]{{#1#2}}\)
\(\newcommand {\mathrlap }[2][]{{#1#2}}\)
\(\newcommand {\mathclap }[2][]{{#1#2}}\)
\(\newcommand {\mathmbox }[1]{#1}\)
\(\newcommand {\clap }[1]{#1}\)
\(\newcommand {\LWRmathmakebox }[2][]{#2}\)
\(\newcommand {\mathmakebox }[1][]{\LWRmathmakebox }\)
\(\newcommand {\cramped }[2][]{{#1#2}}\)
\(\newcommand {\crampedllap }[2][]{{#1#2}}\)
\(\newcommand {\crampedrlap }[2][]{{#1#2}}\)
\(\newcommand {\crampedclap }[2][]{{#1#2}}\)
\(\newenvironment {crampedsubarray}[1]{}{}\)
\(\newcommand {\crampedsubstack }{}\)
\(\newcommand {\smashoperator }[2][]{#2\limits }\)
\(\newcommand {\adjustlimits }{}\)
\(\newcommand {\SwapAboveDisplaySkip }{}\)
\(\require {extpfeil}\)
\(\Newextarrow \xleftrightarrow {10,10}{0x2194}\)
\(\Newextarrow \xLeftarrow {10,10}{0x21d0}\)
\(\Newextarrow \xhookleftarrow {10,10}{0x21a9}\)
\(\Newextarrow \xmapsto {10,10}{0x21a6}\)
\(\Newextarrow \xRightarrow {10,10}{0x21d2}\)
\(\Newextarrow \xLeftrightarrow {10,10}{0x21d4}\)
\(\Newextarrow \xhookrightarrow {10,10}{0x21aa}\)
\(\Newextarrow \xrightharpoondown {10,10}{0x21c1}\)
\(\Newextarrow \xleftharpoondown {10,10}{0x21bd}\)
\(\Newextarrow \xrightleftharpoons {10,10}{0x21cc}\)
\(\Newextarrow \xrightharpoonup {10,10}{0x21c0}\)
\(\Newextarrow \xleftharpoonup {10,10}{0x21bc}\)
\(\Newextarrow \xleftrightharpoons {10,10}{0x21cb}\)
\(\newcommand {\LWRdounderbracket }[3]{\underset {#3}{\underline {#1}}}\)
\(\newcommand {\LWRunderbracket }[2][]{\LWRdounderbracket {#2}}\)
\(\newcommand {\underbracket }[1][]{\LWRunderbracket }\)
\(\newcommand {\LWRdooverbracket }[3]{\overset {#3}{\overline {#1}}}\)
\(\newcommand {\LWRoverbracket }[2][]{\LWRdooverbracket {#2}}\)
\(\newcommand {\overbracket }[1][]{\LWRoverbracket }\)
\(\newcommand {\LATEXunderbrace }[1]{\underbrace {#1}}\)
\(\newcommand {\LATEXoverbrace }[1]{\overbrace {#1}}\)
\(\newenvironment {matrix*}[1][]{\begin {matrix}}{\end {matrix}}\)
\(\newenvironment {pmatrix*}[1][]{\begin {pmatrix}}{\end {pmatrix}}\)
\(\newenvironment {bmatrix*}[1][]{\begin {bmatrix}}{\end {bmatrix}}\)
\(\newenvironment {Bmatrix*}[1][]{\begin {Bmatrix}}{\end {Bmatrix}}\)
\(\newenvironment {vmatrix*}[1][]{\begin {vmatrix}}{\end {vmatrix}}\)
\(\newenvironment {Vmatrix*}[1][]{\begin {Vmatrix}}{\end {Vmatrix}}\)
\(\newenvironment {smallmatrix*}[1][]{\begin {matrix}}{\end {matrix}}\)
\(\newenvironment {psmallmatrix*}[1][]{\begin {pmatrix}}{\end {pmatrix}}\)
\(\newenvironment {bsmallmatrix*}[1][]{\begin {bmatrix}}{\end {bmatrix}}\)
\(\newenvironment {Bsmallmatrix*}[1][]{\begin {Bmatrix}}{\end {Bmatrix}}\)
\(\newenvironment {vsmallmatrix*}[1][]{\begin {vmatrix}}{\end {vmatrix}}\)
\(\newenvironment {Vsmallmatrix*}[1][]{\begin {Vmatrix}}{\end {Vmatrix}}\)
\(\newenvironment {psmallmatrix}[1][]{\begin {pmatrix}}{\end {pmatrix}}\)
\(\newenvironment {bsmallmatrix}[1][]{\begin {bmatrix}}{\end {bmatrix}}\)
\(\newenvironment {Bsmallmatrix}[1][]{\begin {Bmatrix}}{\end {Bmatrix}}\)
\(\newenvironment {vsmallmatrix}[1][]{\begin {vmatrix}}{\end {vmatrix}}\)
\(\newenvironment {Vsmallmatrix}[1][]{\begin {Vmatrix}}{\end {Vmatrix}}\)
\(\newcommand {\LWRmultlined }[1][]{\begin {multline*}}\)
\(\newenvironment {multlined}[1][]{\LWRmultlined }{\end {multline*}}\)
\(\let \LWRorigshoveleft \shoveleft \)
\(\renewcommand {\shoveleft }[1][]{\LWRorigshoveleft }\)
\(\let \LWRorigshoveright \shoveright \)
\(\renewcommand {\shoveright }[1][]{\LWRorigshoveright }\)
\(\newenvironment {dcases}{\begin {cases}}{\end {cases}}\)
\(\newenvironment {dcases*}{\begin {cases}}{\end {cases}}\)
\(\newenvironment {rcases}{\begin {cases}}{\end {cases}}\)
\(\newenvironment {rcases*}{\begin {cases}}{\end {cases}}\)
\(\newenvironment {drcases}{\begin {cases}}{\end {cases}}\)
\(\newenvironment {drcases*}{\begin {cases}}{\end {cases}}\)
\(\newenvironment {cases*}{\begin {cases}}{\end {cases}}\)
\(\newcommand {\MoveEqLeft }[1][]{}\)
\(\def \LWRAboxed #1!|!{\fbox {\(#1\)}&\fbox {\(#2\)}} \newcommand {\Aboxed }[1]{\LWRAboxed #1&&!|!} \)
\( \newcommand {\LWRABLines }[1][\Updownarrow ]{#1 \notag \\}\newcommand {\ArrowBetweenLines }{\ifstar \LWRABLines \LWRABLines } \)
\(\newcommand {\shortintertext }[1]{\text {#1}\notag \\}\)
\(\newcommand {\vdotswithin }[1]{\hspace {.5em}\vdots }\)
\(\newcommand {\LWRshortvdotswithinstar }[1]{\vdots \hspace {.5em} & \\}\)
\(\newcommand {\LWRshortvdotswithinnostar }[1]{& \hspace {.5em}\vdots \\}\)
\(\newcommand {\shortvdotswithin }{\ifstar \LWRshortvdotswithinstar \LWRshortvdotswithinnostar }\)
\(\newcommand {\MTFlushSpaceAbove }{}\)
\(\newcommand {\MTFlushSpaceBelow }{\\}\)
\(\newcommand \lparen {(}\)
\(\newcommand \rparen {)}\)
\(\newcommand {\ordinarycolon }{:}\)
\(\newcommand {\vcentcolon }{\mathrel {\mathop \ordinarycolon }}\)
\(\newcommand \dblcolon {\vcentcolon \vcentcolon }\)
\(\newcommand \coloneqq {\vcentcolon =}\)
\(\newcommand \Coloneqq {\dblcolon =}\)
\(\newcommand \coloneq {\vcentcolon {-}}\)
\(\newcommand \Coloneq {\dblcolon {-}}\)
\(\newcommand \eqqcolon {=\vcentcolon }\)
\(\newcommand \Eqqcolon {=\dblcolon }\)
\(\newcommand \eqcolon {\mathrel {-}\vcentcolon }\)
\(\newcommand \Eqcolon {\mathrel {-}\dblcolon }\)
\(\newcommand \colonapprox {\vcentcolon \approx }\)
\(\newcommand \Colonapprox {\dblcolon \approx }\)
\(\newcommand \colonsim {\vcentcolon \sim }\)
\(\newcommand \Colonsim {\dblcolon \sim }\)
\(\newcommand {\nuparrow }{\mathrel {\cancel {\uparrow }}}\)
\(\newcommand {\ndownarrow }{\mathrel {\cancel {\downarrow }}}\)
\(\newcommand {\bigtimes }{\mathop {\Large \times }\limits }\)
\(\newcommand {\prescript }[3]{{}^{#1}_{#2}#3}\)
\(\newenvironment {lgathered}{\begin {gathered}}{\end {gathered}}\)
\(\newenvironment {rgathered}{\begin {gathered}}{\end {gathered}}\)
\(\newcommand {\splitfrac }[2]{{}^{#1}_{#2}}\)
\(\let \splitdfrac \splitfrac \)
\(\newcommand {\LWRoverlaysymbols }[2]{\mathord {\smash {\mathop {#2\strut }\limits ^{\smash {\lower 3ex{#1}}}}\strut }}\)
\(\newcommand{\alphaup}{\unicode{x03B1}}\)
\(\newcommand{\betaup}{\unicode{x03B2}}\)
\(\newcommand{\gammaup}{\unicode{x03B3}}\)
\(\newcommand{\digammaup}{\unicode{x03DD}}\)
\(\newcommand{\deltaup}{\unicode{x03B4}}\)
\(\newcommand{\epsilonup}{\unicode{x03F5}}\)
\(\newcommand{\varepsilonup}{\unicode{x03B5}}\)
\(\newcommand{\zetaup}{\unicode{x03B6}}\)
\(\newcommand{\etaup}{\unicode{x03B7}}\)
\(\newcommand{\thetaup}{\unicode{x03B8}}\)
\(\newcommand{\varthetaup}{\unicode{x03D1}}\)
\(\newcommand{\iotaup}{\unicode{x03B9}}\)
\(\newcommand{\kappaup}{\unicode{x03BA}}\)
\(\newcommand{\varkappaup}{\unicode{x03F0}}\)
\(\newcommand{\lambdaup}{\unicode{x03BB}}\)
\(\newcommand{\muup}{\unicode{x03BC}}\)
\(\newcommand{\nuup}{\unicode{x03BD}}\)
\(\newcommand{\xiup}{\unicode{x03BE}}\)
\(\newcommand{\omicronup}{\unicode{x03BF}}\)
\(\newcommand{\piup}{\unicode{x03C0}}\)
\(\newcommand{\varpiup}{\unicode{x03D6}}\)
\(\newcommand{\rhoup}{\unicode{x03C1}}\)
\(\newcommand{\varrhoup}{\unicode{x03F1}}\)
\(\newcommand{\sigmaup}{\unicode{x03C3}}\)
\(\newcommand{\varsigmaup}{\unicode{x03C2}}\)
\(\newcommand{\tauup}{\unicode{x03C4}}\)
\(\newcommand{\upsilonup}{\unicode{x03C5}}\)
\(\newcommand{\phiup}{\unicode{x03D5}}\)
\(\newcommand{\varphiup}{\unicode{x03C6}}\)
\(\newcommand{\chiup}{\unicode{x03C7}}\)
\(\newcommand{\psiup}{\unicode{x03C8}}\)
\(\newcommand{\omegaup}{\unicode{x03C9}}\)
\(\newcommand{\Alphaup}{\unicode{x0391}}\)
\(\newcommand{\Betaup}{\unicode{x0392}}\)
\(\newcommand{\Gammaup}{\unicode{x0393}}\)
\(\newcommand{\Digammaup}{\unicode{x03DC}}\)
\(\newcommand{\Deltaup}{\unicode{x0394}}\)
\(\newcommand{\Epsilonup}{\unicode{x0395}}\)
\(\newcommand{\Zetaup}{\unicode{x0396}}\)
\(\newcommand{\Etaup}{\unicode{x0397}}\)
\(\newcommand{\Thetaup}{\unicode{x0398}}\)
\(\newcommand{\Varthetaup}{\unicode{x03F4}}\)
\(\newcommand{\Iotaup}{\unicode{x0399}}\)
\(\newcommand{\Kappaup}{\unicode{x039A}}\)
\(\newcommand{\Lambdaup}{\unicode{x039B}}\)
\(\newcommand{\Muup}{\unicode{x039C}}\)
\(\newcommand{\Nuup}{\unicode{x039D}}\)
\(\newcommand{\Xiup}{\unicode{x039E}}\)
\(\newcommand{\Omicronup}{\unicode{x039F}}\)
\(\newcommand{\Piup}{\unicode{x03A0}}\)
\(\newcommand{\Varpiup}{\unicode{x03D6}}\)
\(\newcommand{\Rhoup}{\unicode{x03A1}}\)
\(\newcommand{\Sigmaup}{\unicode{x03A3}}\)
\(\newcommand{\Tauup}{\unicode{x03A4}}\)
\(\newcommand{\Upsilonup}{\unicode{x03A5}}\)
\(\newcommand{\Phiup}{\unicode{x03A6}}\)
\(\newcommand{\Chiup}{\unicode{x03A7}}\)
\(\newcommand{\Psiup}{\unicode{x03A8}}\)
\(\newcommand{\Omegaup}{\unicode{x03A9}}\)
\(\newcommand{\alphait}{\unicode{x1D6FC}}\)
\(\newcommand{\betait}{\unicode{x1D6FD}}\)
\(\newcommand{\gammait}{\unicode{x1D6FE}}\)
\(\newcommand{\digammait}{\mathit{\unicode{x03DD}}}\)
\(\newcommand{\deltait}{\unicode{x1D6FF}}\)
\(\newcommand{\epsilonit}{\unicode{x1D716}}\)
\(\newcommand{\varepsilonit}{\unicode{x1D700}}\)
\(\newcommand{\zetait}{\unicode{x1D701}}\)
\(\newcommand{\etait}{\unicode{x1D702}}\)
\(\newcommand{\thetait}{\unicode{x1D703}}\)
\(\newcommand{\varthetait}{\unicode{x1D717}}\)
\(\newcommand{\iotait}{\unicode{x1D704}}\)
\(\newcommand{\kappait}{\unicode{x1D705}}\)
\(\newcommand{\varkappait}{\unicode{x1D718}}\)
\(\newcommand{\lambdait}{\unicode{x1D706}}\)
\(\newcommand{\muit}{\unicode{x1D707}}\)
\(\newcommand{\nuit}{\unicode{x1D708}}\)
\(\newcommand{\xiit}{\unicode{x1D709}}\)
\(\newcommand{\omicronit}{\unicode{x1D70A}}\)
\(\newcommand{\piit}{\unicode{x1D70B}}\)
\(\newcommand{\varpiit}{\unicode{x1D71B}}\)
\(\newcommand{\rhoit}{\unicode{x1D70C}}\)
\(\newcommand{\varrhoit}{\unicode{x1D71A}}\)
\(\newcommand{\sigmait}{\unicode{x1D70E}}\)
\(\newcommand{\varsigmait}{\unicode{x1D70D}}\)
\(\newcommand{\tauit}{\unicode{x1D70F}}\)
\(\newcommand{\upsilonit}{\unicode{x1D710}}\)
\(\newcommand{\phiit}{\unicode{x1D719}}\)
\(\newcommand{\varphiit}{\unicode{x1D711}}\)
\(\newcommand{\chiit}{\unicode{x1D712}}\)
\(\newcommand{\psiit}{\unicode{x1D713}}\)
\(\newcommand{\omegait}{\unicode{x1D714}}\)
\(\newcommand{\Alphait}{\unicode{x1D6E2}}\)
\(\newcommand{\Betait}{\unicode{x1D6E3}}\)
\(\newcommand{\Gammait}{\unicode{x1D6E4}}\)
\(\newcommand{\Digammait}{\mathit{\unicode{x03DC}}}\)
\(\newcommand{\Deltait}{\unicode{x1D6E5}}\)
\(\newcommand{\Epsilonit}{\unicode{x1D6E6}}\)
\(\newcommand{\Zetait}{\unicode{x1D6E7}}\)
\(\newcommand{\Etait}{\unicode{x1D6E8}}\)
\(\newcommand{\Thetait}{\unicode{x1D6E9}}\)
\(\newcommand{\Varthetait}{\unicode{x1D6F3}}\)
\(\newcommand{\Iotait}{\unicode{x1D6EA}}\)
\(\newcommand{\Kappait}{\unicode{x1D6EB}}\)
\(\newcommand{\Lambdait}{\unicode{x1D6EC}}\)
\(\newcommand{\Muit}{\unicode{x1D6ED}}\)
\(\newcommand{\Nuit}{\unicode{x1D6EE}}\)
\(\newcommand{\Xiit}{\unicode{x1D6EF}}\)
\(\newcommand{\Omicronit}{\unicode{x1D6F0}}\)
\(\newcommand{\Piit}{\unicode{x1D6F1}}\)
\(\newcommand{\Rhoit}{\unicode{x1D6F2}}\)
\(\newcommand{\Sigmait}{\unicode{x1D6F4}}\)
\(\newcommand{\Tauit}{\unicode{x1D6F5}}\)
\(\newcommand{\Upsilonit}{\unicode{x1D6F6}}\)
\(\newcommand{\Phiit}{\unicode{x1D6F7}}\)
\(\newcommand{\Chiit}{\unicode{x1D6F8}}\)
\(\newcommand{\Psiit}{\unicode{x1D6F9}}\)
\(\newcommand{\Omegait}{\unicode{x1D6FA}}\)
\(\let \digammaup \Digammaup \)
\(\renewcommand {\digammait }{\mathit {\digammaup }}\)
\(\newcommand {\smallin }{\unicode {x220A}}\)
\(\newcommand {\smallowns }{\unicode {x220D}}\)
\(\newcommand {\notsmallin }{\LWRoverlaysymbols {/}{\unicode {x220A}}}\)
\(\newcommand {\notsmallowns }{\LWRoverlaysymbols {/}{\unicode {x220D}}}\)
\(\newcommand {\rightangle }{\unicode {x221F}}\)
\(\newcommand {\intclockwise }{\unicode {x2231}}\)
\(\newcommand {\ointclockwise }{\unicode {x2232}}\)
\(\newcommand {\ointctrclockwise }{\unicode {x2233}}\)
\(\newcommand {\oiint }{\unicode {x222F}}\)
\(\newcommand {\oiiint }{\unicode {x2230}}\)
\(\newcommand {\ddag }{\unicode {x2021}}\)
\(\newcommand {\P }{\unicode {x00B6}}\)
\(\newcommand {\copyright }{\unicode {x00A9}}\)
\(\newcommand {\dag }{\unicode {x2020}}\)
\(\newcommand {\pounds }{\unicode {x00A3}}\)
\(\newcommand {\iddots }{\unicode {x22F0}}\)
\(\newcommand {\utimes }{\overline {\times }}\)
\(\newcommand {\dtimes }{\underline {\times }}\)
\(\newcommand {\udtimes }{\overline {\underline {\times }}}\)
\(\newcommand {\leftwave }{\left \{}\)
\(\newcommand {\rightwave }{\right \}}\)
\(\newcommand {\toprule }[1][]{\hline }\)
\(\let \midrule \toprule \)
\(\let \bottomrule \toprule \)
\(\newcommand {\cmidrule }[2][]{}\)
\(\newcommand {\morecmidrules }{}\)
\(\newcommand {\specialrule }[3]{\hline }\)
\(\newcommand {\addlinespace }[1][]{}\)
\(\newcommand {\LWRsubmultirow }[2][]{#2}\)
\(\newcommand {\LWRmultirow }[2][]{\LWRsubmultirow }\)
\(\newcommand {\multirow }[2][]{\LWRmultirow }\)
\(\newcommand {\mrowcell }{}\)
\(\newcommand {\mcolrowcell }{}\)
\(\newcommand {\STneed }[1]{}\)
\( \newcommand {\multicolumn }[3]{#3}\)
\(\newcommand {\tothe }[1]{^{#1}}\)
\(\newcommand {\raiseto }[2]{{#2}^{#1}}\)
\(\newcommand {\ang }[2][]{(\mathrm {#2})\degree }\)
\(\newcommand {\num }[2][]{\mathrm {#2}}\)
\(\newcommand {\si }[2][]{\mathrm {#2}}\)
\(\newcommand {\LWRSI }[2][]{\mathrm {#1\LWRSInumber \,#2}}\)
\(\newcommand {\SI }[2][]{\def \LWRSInumber {#2}\LWRSI }\)
\(\newcommand {\numlist }[2][]{\mathrm {#2}}\)
\(\newcommand {\numrange }[3][]{\mathrm {#2\,\unicode {x2013}\,#3}}\)
\(\newcommand {\SIlist }[3][]{\mathrm {#2\,#3}}\)
\(\newcommand {\SIrange }[4][]{\mathrm {#2\,#4\,\unicode {x2013}\,#3\,#4}}\)
\(\newcommand {\tablenum }[2][]{\mathrm {#2}}\)
\(\newcommand {\ampere }{\mathrm {A}}\)
\(\newcommand {\candela }{\mathrm {cd}}\)
\(\newcommand {\kelvin }{\mathrm {K}}\)
\(\newcommand {\kilogram }{\mathrm {kg}}\)
\(\newcommand {\metre }{\mathrm {m}}\)
\(\newcommand {\mole }{\mathrm {mol}}\)
\(\newcommand {\second }{\mathrm {s}}\)
\(\newcommand {\becquerel }{\mathrm {Bq}}\)
\(\newcommand {\degreeCelsius }{\unicode {x2103}}\)
\(\newcommand {\coulomb }{\mathrm {C}}\)
\(\newcommand {\farad }{\mathrm {F}}\)
\(\newcommand {\gray }{\mathrm {Gy}}\)
\(\newcommand {\hertz }{\mathrm {Hz}}\)
\(\newcommand {\henry }{\mathrm {H}}\)
\(\newcommand {\joule }{\mathrm {J}}\)
\(\newcommand {\katal }{\mathrm {kat}}\)
\(\newcommand {\lumen }{\mathrm {lm}}\)
\(\newcommand {\lux }{\mathrm {lx}}\)
\(\newcommand {\newton }{\mathrm {N}}\)
\(\newcommand {\ohm }{\mathrm {\Omega }}\)
\(\newcommand {\pascal }{\mathrm {Pa}}\)
\(\newcommand {\radian }{\mathrm {rad}}\)
\(\newcommand {\siemens }{\mathrm {S}}\)
\(\newcommand {\sievert }{\mathrm {Sv}}\)
\(\newcommand {\steradian }{\mathrm {sr}}\)
\(\newcommand {\tesla }{\mathrm {T}}\)
\(\newcommand {\volt }{\mathrm {V}}\)
\(\newcommand {\watt }{\mathrm {W}}\)
\(\newcommand {\weber }{\mathrm {Wb}}\)
\(\newcommand {\day }{\mathrm {d}}\)
\(\newcommand {\degree }{\mathrm {^\circ }}\)
\(\newcommand {\hectare }{\mathrm {ha}}\)
\(\newcommand {\hour }{\mathrm {h}}\)
\(\newcommand {\litre }{\mathrm {l}}\)
\(\newcommand {\liter }{\mathrm {L}}\)
\(\newcommand {\arcminute }{^\prime }\)
\(\newcommand {\minute }{\mathrm {min}}\)
\(\newcommand {\arcsecond }{^{\prime \prime }}\)
\(\newcommand {\tonne }{\mathrm {t}}\)
\(\newcommand {\astronomicalunit }{au}\)
\(\newcommand {\atomicmassunit }{u}\)
\(\newcommand {\bohr }{\mathit {a}_0}\)
\(\newcommand {\clight }{\mathit {c}_0}\)
\(\newcommand {\dalton }{\mathrm {D}_\mathrm {a}}\)
\(\newcommand {\electronmass }{\mathit {m}_{\mathrm {e}}}\)
\(\newcommand {\electronvolt }{\mathrm {eV}}\)
\(\newcommand {\elementarycharge }{\mathit {e}}\)
\(\newcommand {\hartree }{\mathit {E}_{\mathrm {h}}}\)
\(\newcommand {\planckbar }{\mathit {\unicode {x210F}}}\)
\(\newcommand {\angstrom }{\mathrm {\unicode {x212B}}}\)
\(\let \LWRorigbar \bar \)
\(\newcommand {\bar }{\mathrm {bar}}\)
\(\newcommand {\barn }{\mathrm {b}}\)
\(\newcommand {\bel }{\mathrm {B}}\)
\(\newcommand {\decibel }{\mathrm {dB}}\)
\(\newcommand {\knot }{\mathrm {kn}}\)
\(\newcommand {\mmHg }{\mathrm {mmHg}}\)
\(\newcommand {\nauticalmile }{\mathrm {M}}\)
\(\newcommand {\neper }{\mathrm {Np}}\)
\(\newcommand {\yocto }{\mathrm {y}}\)
\(\newcommand {\zepto }{\mathrm {z}}\)
\(\newcommand {\atto }{\mathrm {a}}\)
\(\newcommand {\femto }{\mathrm {f}}\)
\(\newcommand {\pico }{\mathrm {p}}\)
\(\newcommand {\nano }{\mathrm {n}}\)
\(\newcommand {\micro }{\mathrm {\unicode {x00B5}}}\)
\(\newcommand {\milli }{\mathrm {m}}\)
\(\newcommand {\centi }{\mathrm {c}}\)
\(\newcommand {\deci }{\mathrm {d}}\)
\(\newcommand {\deca }{\mathrm {da}}\)
\(\newcommand {\hecto }{\mathrm {h}}\)
\(\newcommand {\kilo }{\mathrm {k}}\)
\(\newcommand {\mega }{\mathrm {M}}\)
\(\newcommand {\giga }{\mathrm {G}}\)
\(\newcommand {\tera }{\mathrm {T}}\)
\(\newcommand {\peta }{\mathrm {P}}\)
\(\newcommand {\exa }{\mathrm {E}}\)
\(\newcommand {\zetta }{\mathrm {Z}}\)
\(\newcommand {\yotta }{\mathrm {Y}}\)
\(\newcommand {\percent }{\mathrm {\%}}\)
\(\newcommand {\meter }{\mathrm {m}}\)
\(\newcommand {\metre }{\mathrm {m}}\)
\(\newcommand {\gram }{\mathrm {g}}\)
\(\newcommand {\kg }{\kilo \gram }\)
\(\newcommand {\of }[1]{_{\mathrm {#1}}}\)
\(\newcommand {\squared }{^2}\)
\(\newcommand {\square }[1]{\mathrm {#1}^2}\)
\(\newcommand {\cubed }{^3}\)
\(\newcommand {\cubic }[1]{\mathrm {#1}^3}\)
\(\newcommand {\per }{/}\)
\(\newcommand {\celsius }{\unicode {x2103}}\)
\(\newcommand {\fg }{\femto \gram }\)
\(\newcommand {\pg }{\pico \gram }\)
\(\newcommand {\ng }{\nano \gram }\)
\(\newcommand {\ug }{\micro \gram }\)
\(\newcommand {\mg }{\milli \gram }\)
\(\newcommand {\g }{\gram }\)
\(\newcommand {\kg }{\kilo \gram }\)
\(\newcommand {\amu }{\mathrm {u}}\)
\(\newcommand {\nm }{\nano \metre }\)
\(\newcommand {\um }{\micro \metre }\)
\(\newcommand {\mm }{\milli \metre }\)
\(\newcommand {\cm }{\centi \metre }\)
\(\newcommand {\dm }{\deci \metre }\)
\(\newcommand {\m }{\metre }\)
\(\newcommand {\km }{\kilo \metre }\)
\(\newcommand {\as }{\atto \second }\)
\(\newcommand {\fs }{\femto \second }\)
\(\newcommand {\ps }{\pico \second }\)
\(\newcommand {\ns }{\nano \second }\)
\(\newcommand {\us }{\micro \second }\)
\(\newcommand {\ms }{\milli \second }\)
\(\newcommand {\s }{\second }\)
\(\newcommand {\fmol }{\femto \mol }\)
\(\newcommand {\pmol }{\pico \mol }\)
\(\newcommand {\nmol }{\nano \mol }\)
\(\newcommand {\umol }{\micro \mol }\)
\(\newcommand {\mmol }{\milli \mol }\)
\(\newcommand {\mol }{\mol }\)
\(\newcommand {\kmol }{\kilo \mol }\)
\(\newcommand {\pA }{\pico \ampere }\)
\(\newcommand {\nA }{\nano \ampere }\)
\(\newcommand {\uA }{\micro \ampere }\)
\(\newcommand {\mA }{\milli \ampere }\)
\(\newcommand {\A }{\ampere }\)
\(\newcommand {\kA }{\kilo \ampere }\)
\(\newcommand {\ul }{\micro \litre }\)
\(\newcommand {\ml }{\milli \litre }\)
\(\newcommand {\l }{\litre }\)
\(\newcommand {\hl }{\hecto \litre }\)
\(\newcommand {\uL }{\micro \liter }\)
\(\newcommand {\mL }{\milli \liter }\)
\(\newcommand {\L }{\liter }\)
\(\newcommand {\hL }{\hecto \liter }\)
\(\newcommand {\mHz }{\milli \hertz }\)
\(\newcommand {\Hz }{\hertz }\)
\(\newcommand {\kHz }{\kilo \hertz }\)
\(\newcommand {\MHz }{\mega \hertz }\)
\(\newcommand {\GHz }{\giga \hertz }\)
\(\newcommand {\THz }{\tera \hertz }\)
\(\newcommand {\mN }{\milli \newton }\)
\(\newcommand {\N }{\newton }\)
\(\newcommand {\kN }{\kilo \newton }\)
\(\newcommand {\MN }{\mega \newton }\)
\(\newcommand {\Pa }{\pascal }\)
\(\newcommand {\kPa }{\kilo \pascal }\)
\(\newcommand {\MPa }{\mega \pascal }\)
\(\newcommand {\GPa }{\giga \pascal }\)
\(\newcommand {\mohm }{\milli \ohm }\)
\(\newcommand {\kohm }{\kilo \ohm }\)
\(\newcommand {\Mohm }{\mega \ohm }\)
\(\newcommand {\pV }{\pico \volt }\)
\(\newcommand {\nV }{\nano \volt }\)
\(\newcommand {\uV }{\micro \volt }\)
\(\newcommand {\mV }{\milli \volt }\)
\(\newcommand {\V }{\volt }\)
\(\newcommand {\kV }{\kilo \volt }\)
\(\newcommand {\W }{\watt }\)
\(\newcommand {\uW }{\micro \watt }\)
\(\newcommand {\mW }{\milli \watt }\)
\(\newcommand {\kW }{\kilo \watt }\)
\(\newcommand {\MW }{\mega \watt }\)
\(\newcommand {\GW }{\giga \watt }\)
\(\newcommand {\J }{\joule }\)
\(\newcommand {\uJ }{\micro \joule }\)
\(\newcommand {\mJ }{\milli \joule }\)
\(\newcommand {\kJ }{\kilo \joule }\)
\(\newcommand {\eV }{\electronvolt }\)
\(\newcommand {\meV }{\milli \electronvolt }\)
\(\newcommand {\keV }{\kilo \electronvolt }\)
\(\newcommand {\MeV }{\mega \electronvolt }\)
\(\newcommand {\GeV }{\giga \electronvolt }\)
\(\newcommand {\TeV }{\tera \electronvolt }\)
\(\newcommand {\kWh }{\kilo \watt \hour }\)
\(\newcommand {\F }{\farad }\)
\(\newcommand {\fF }{\femto \farad }\)
\(\newcommand {\pF }{\pico \farad }\)
\(\newcommand {\K }{\mathrm {K}}\)
\(\newcommand {\dB }{\mathrm {dB}}\)
\(\newcommand {\kibi }{\mathrm {Ki}}\)
\(\newcommand {\mebi }{\mathrm {Mi}}\)
\(\newcommand {\gibi }{\mathrm {Gi}}\)
\(\newcommand {\tebi }{\mathrm {Ti}}\)
\(\newcommand {\pebi }{\mathrm {Pi}}\)
\(\newcommand {\exbi }{\mathrm {Ei}}\)
\(\newcommand {\zebi }{\mathrm {Zi}}\)
\(\newcommand {\yobi }{\mathrm {Yi}}\)
\(\require {mhchem}\)
\(\require {cancel}\)
\(\newcommand {\fint }{âĺŊ}\)
\(\newcommand {\hdots }{\cdots }\)
\(\newcommand {\mathnormal }[1]{#1}\)
\(\newcommand {\vecs }[2]{\vec {#1}_{#2}}\)
\(\renewcommand {\A }{\mathcal {A}}\)
\(\newcommand {\D }{\mathcal {D}}\)
\(\renewcommand {\H }{\mathcal {H}}\)
\(\renewcommand {\L }{\mathcal {L}}\)
\(\renewcommand {\O }{\mathcal {O}}\)
\(\renewcommand {\P }{\mathcal {P}}\)
\(\newcommand {\T }{\mathcal {T}}\)
\(\newcommand {\EE }{\mathbb {E}}\)
\(\newcommand {\PP }{\mathbb {P}}\)
\(\newcommand {\DT }{\operatorname {DT}}\)
\(\newcommand {\dcup }{\mathbin {\dot {\cup }}}\)
\(\newcommand {\parent }{\operatorname {parent}}\)
\(\newcommand {\cc }{\operatorname {cc}}\)
\(\newcommand {\interior }{\operatorname {int}}\)
\(\newcommand {\CH }{\operatorname {CH}}\)
\(\newcommand {\sgn }{\operatorname {sgn}}\)
\(\newcommand {\zone }{\operatorname {zone}}\)
\(\newcommand {\code }[1]{\texttt {#1}}\)
\(\newcommand {\name }[1]{\textsc {#1}}\)
\(\newcommand {\smallpmatrix }[1]{\left (\begin {smallmatrix}#1\end {smallmatrix}\right )}\)
\(\newcommand {\matlab }{{\fontfamily {bch}\scshape \selectfont {}Matlab}}\)
\(\newcommand {\innerproduct }[1]{\left \langle {#1}\right \rangle }\)
\(\newcommand {\norm }[1]{\left \Vert {#1}\right \Vert }\)
\(\renewcommand {\natural }{\mathbb {N}}\)
\(\newcommand {\integer }{\mathbb {Z}}\)
\(\newcommand {\rational }{\mathbb {Q}}\)
\(\newcommand {\real }{\mathbb {R}}\)
\(\newcommand {\complex }{\mathbb {C}}\)
\(\renewcommand {\d }{\mathop {}\!\mathrm {d}}\)
\(\newcommand {\dr }{\d {}r}\)
\(\newcommand {\ds }{\d {}s}\)
\(\newcommand {\dt }{\d {}t}\)
\(\newcommand {\du }{\d {}u}\)
\(\newcommand {\dv }{\d {}v}\)
\(\newcommand {\dw }{\d {}w}\)
\(\newcommand {\dx }{\d {}x}\)
\(\newcommand {\dy }{\d {}y}\)
\(\newcommand {\dz }{\d {}z}\)
\(\newcommand {\dsigma }{\d {}\sigma }\)
\(\newcommand {\dphi }{\d {}\phi }\)
\(\newcommand {\dvarphi }{\d {}\varphi }\)
\(\newcommand {\dtau }{\d {}\tau }\)
\(\newcommand {\dxi }{\d {}\xi }\)
\(\newcommand {\dtheta }{\d {}\theta }\)
\(\newcommand {\tp }{\mathrm {T}}\)
Wiederholung: Suchbäume
Baum: Ein Baum ist ein kreisfreier, gerichteter Graph, der genau einen Knoten mit Eingangsgrad \(0\) besitzt. Dieser wird Wurzel genannt. Zeigt eine Kante von einem Knoten \(v_1\) zu einem Knoten \(v_2\), so heißt \(v_1\) Vater \(\parent (v_1)\) von \(v_2\) und \(v_2\) Kind von \(v_1\). Knoten ohne Kinder heißen Blätter, die anderen Knoten heißen innere
Knoten. Der Teilbaum eines inneren Knotens \(v\) ist der Baum besteht aus den Kindern von \(v\), deren Kindern usw. mit \(v\) als Wurzel. Die Tiefe eines Knotens ist die Länge des kürzesten Pfads von der Wurzel zu diesem Knoten. Die Höhe des Baums ist
die Tiefe des tiefsten Knotens.
2-4-Baum: Sei \(P = \{a_1, \dotsc , a_n\}\) eine total geordnete Menge. Ein 2-4-Baum ist ein Baum, in dem \(P\) strukturiert gespeichert wird. \(P\) wird nur in den
Blättern des Baums gespeichert, diese müssen sortiert sein. Die Blätter müssen alle die gleiche Tiefe haben. Für jeden inneren Knoten \(v\) mit \(i\) Kindern muss gelten, dass \(2
\le i \le 4\), und \(v\) muss \(i - 1\) Schlüssel enthalten, wobei der \(j\)-te Schlüssel das größte Element des \(j\)-ten Teilbaums von \(v\) ist (für \(j = 1, \dotsc , i - 1\)).
Oftmals geht man davon aus, dass die Blätter doppelt verkettet sind.
Zeit-/Platzaufwand: Ein 2-4-Baum mit \(n\) Blättern besitzt die Höhe \(\O (\log n)\). Das Suchen, Einfügen und Löschen eines Elements besitzt den Zeitaufwand \(\O (\log
n)\). Die Konstruktion eines 2-4-Baums für \(n\) Elemente besitzt den Zeitaufwand \(\O (n \log n)\) (sind die Elemente sortiert, dann sogar nur \(\O (n)\)). Der Baum besitzt \(\le n\) innere Knoten, damit ist der
Platzaufwand \(\O (n)\).
Binärbaum: Ein Binärbaum ist ein Baum, bei dem jeder Knoten höchstens zwei Blätter besitzt und jedes Blatt entweder ein
linkes Kind oder ein rechtes Kind ist. Er heißt voll, falls jeder innere Knoten genau
zwei Kinder besitzt. Ein voller Binärbaum heißt vollständig balanciert, falls alle Kinder dieselbe Tiefe haben. Ein Binärbaum heißt balanciert, falls er „fast“ vollständig balanciert ist.
Zeit-/Platzaufwand: Ein vollständig balancierter Binärbaum besitzt die Höhe \(\O (\log n)\) und \(\le n\) innere Knoten, damit ist der Platzaufwand \(\O (n)\).
Suchbaum: „Suchbaum“ ist ein allgemeiner Begriff für einen Baum, bei dem das Suchen von Elementen effizient möglich ist. Beispiele sind AVL-,
Rot-Schwarz- und 2-4-Bäume sowie binäre Suchbäume. Ihnen allen ist gemeinsam, dass obiger Satz über die Zeit-/Platzkomplexität von 2-4-Bäumen auch für
sie gilt.
Wiederholung: Heaps
Heap: „Heap“ ist ein allgemeiner Begriff für eine Datenstruktur, die eine bestimmte, total geordnete Menge verwaltet. Ein Heap unterstützt zumindest das
Einfügen von Elementen sowie die Rückgabe und das Entfernen des kleinsten Elementes.
(binärer) Min-Heap: Ein (binärer) Min-Heap ist ein Binärbaum, in dessen Knoten Elemente aus einer total geordneten Menge gespeichert
sind, sodass \(\text {key}(v) \ge \text {key}(\parent (v))\) für alle Knoten \(v\) außer der Wurzel gilt (Heap-Eigenschaft). Der Baum ist balanciert (alle Ebenen
voll besetzt, letzte Ebene linksbündig aufgefüllt).
Zeit-/Platzaufwand: Ein Min-Heap besitzt die Höhe \(\O (\log n)\) und verbraucht den Platz \(\O (n)\). Er kann in \(\O (n)\) konstruiert werden. Das Finden des Minimums kostet \(\O (1)\) Zeit, die
anderen Operationen (Löschen des Minimums, Einfügen eines Elements) kosten \(\O (\log n)\).
Range-Bäume
Problem: Gegeben sind \(n\) Punkte \(P = \{a_1, \dotsc , a_n\} \subset \real ^d\) sowie ein achsenparalleles „Rechteck“ (\([l, r]\) für \(d = 1\), \([l, r] \times [u, o]\) für \(d = 2\)
usw.).
Gesucht sind alle Punkte, die in diesem Rechteck liegen (Bereichsabfrage (range query)).
Anwendungen des Problems finden sich nicht nur in der Geometrie, sondern z. B. bei Datenbankabfragen: Wenn die Mitarbeiter einer Firma gesucht sind, deren Geburtstage zwischen zwei bestimmten Daten und deren
Gehälter zwischen zwei bestimmten Zahlen liegen, dann können diese Daten auf Zahlen abgebildet und das Problem mit Range-Bäumen gelöst werden.
Eindimensionaler Fall
naive Lösung: Gehe alle Elemente durch und gebe die passenden Elemente aus.
Zeitaufwand für Abfrage: \(\O (n)\)
bessere Lösung: Ordne die Elemente zunächst in einem Suchbaum. Suche anschließend die linke Grenze \(l\) im Suchbaum. Laufe anschließend durch so viele Blätter, bis die Elemente
größer als \(r\) sind.
Zeitaufwand für Konstruktion: \(\O (n \log n)\)
Zeitaufwand für Abfrage: \(\O (\log n + k)\) mit \(k\) der Anzahl der zurückgegebenen Elemente
Mehrdimensionaler Fall
Im Folgenden sei \(P \subset \real ^2\). Die gezeigten Strukturen/Algorithmen lassen sich verallgemeinern.
erste Idee: Erstelle für jede Dimension einen Suchbaum, sodass die Elemente bzgl. dieser Dimension strukturiert sind. Für eine Bereichsabfrage \([l, r] \times [u, o]\) berechne die Mengen \(E_1\)
und \(E_2\), sodass die \(x\)- bzw. \(y\)-Koordinate der Punkte aus den Mengen in \([l, r]\) bzw. \([u, o]\) liegt. Anschließend schneide \(E_1\) und \(E_2\).
Zeitaufwand für Konstruktion: \(\O (n \log n)\)
Zeitaufwand für Abfrage: \(\O (\log n + k_1 + k_2)\), wenn \(k_1 := |E_1|\) und \(k_2 := |E_2|\) (mit Mengen-Implementationen mit Kosten \(\O (1)\) für „\(\in \)“ geht der Durchschnitt
in Zeit \(\O (k_1 + k_2)\))
Es gibt allerdings Punktmengen, bei denen jeweils \(n/2\) der Punkte über dem Rechteck bzw. rechts vom Rechteck liegen, d. h. \(k_1 + k_2 = n\), allerdings ist die endgültige Ausgabe leer. Gesucht ist
ein ausgabesensitiver (output sensitive) Algorithmus, d. h. ein Algorithmus, dessen Laufzeit von der Ausgabegröße \(k\) abhängt.
Zunächst muss man den eindimensionalen Algorithmus für die Bereichsabfrage modifizieren.
eindimensionale Modifizierung: Suche die linke Grenze \(l\) und die rechte Grenze \(r\) im Suchbaum. Für eine Weile werden die Suchpfade für beide Grenzen gleich sein. Wenn sie sich trennen,
dann wähle ab diesem Punkt beim linken Suchpfad alle Kinder, die rechts von den Suchpfad-Knoten liegen. Analog wähle beim rechte Suchpfad alle Kinder, die links von den Suchpfad-Knoten liegen. Die gesuchte
Punktmenge ist nun genau die (disjunkte) Vereinigung der Blätter der Teilbäume unter den gewählten Kindern. Es gibt \(\O (\log n)\) viele von diesen Teilbäumen, weil in jeder Ebene des
Baums nur \(\O (1)\) viele gewählte Kinder sind.
Zeitaufwand für Abfrage: \(\O (\log n + k)\) (unverändert)
mehrdimensionale Verbesserung: Baue einen Suchbaum über den \(x\)-Koordinaten auf. Speichere in jeden inneren Knoten die Punkte an den Blättern seines Teilbaums in einem Suchbaum
über den \(y\)-Koordinaten. Für eine Bereichsabfrage \([l, r] \times [u, o]\) bestimme Suchpfade wie eben für \(l\) und \(r\) in der Primärstruktur. Anschließend befrage die
Sekundärstrukturen der Knoten, die nach „innen“ von den Suchpfaden hängen.
Zeitaufwand für Abfrage: \(\O (\log ^2 n + k)\) mit \(k\) der Größe der Ausgabe
Beweis: Es gibt \(\O (\log n)\)-viele nach innen hängende Knoten. Das Befragen des \(i\)-ten Knotens kostet Zeit \(\O (\log n + k_i)\). Weil die Blätter der Teilbäume disjunkt sind, gilt
\(\sum _i k_i = k\), d. h. der Zeitaufwand ist \(\O (\log ^2 n + k)\).
Platzaufwand: \(\O (n \log n)\):
Beweis: Der Suchbaum über den \(x\)-Koordinaten (ohne Sekundärstrukturen) benötigt zwar nur \(\O (n)\) Platz. Allerdings wird jedes der \(n\) Blätter in den
Sekundärstrukturen vom Vater, vom Großvater usw. gespeichert, d. h. jeweils \(\O (\log n)\)-mal. Insgesamt benötigt man damit \(\O (n \log n)\) Platz.
mehr Dimensionen:
Für \(d\) Dimensionen benötigt man Zeit \(\O (\log ^d n + k)\) und Platz \(\O (n \log ^{d-1} n)\).
Fractional Cascading
Fractional Cascading: Die \(y\)-Suchvorgänge in den \(\O (\log n)\)-vielen nach innen hängenden Knoten hängen miteinander zusammen. Dies kann man ausnutzen, um den
Abfrage-Zeitaufwand für \(\real ^2\) von \(\O (\log ^2 n + k)\) auf \(\O (\log n + k)\) zu verringern. Die zugehörige Technik nennt man Fractional
Cascading.
Sei \(P = P_1 \dcup P_2\) eine Punktmenge, für die ein eindimensionaler Range-Baum für die \(y\)-Koordinaten konstruiert wurde. Wenn man einen Abfragepunkt \(q\) bzgl. der \(y\)-Koordinate in \(P\)
lokalisiert hat, so kann man \(q\) in \(P_1\) und \(P_2\) in Zeit \(\O (1)\) lokalisieren, indem man Zeiger von jedem \(p \in P\) zu seinem Vorgänger und Nachfolger in \(P_1\) und \(P_2\) speichert. So muss nur eine
Suche (nur in der Wurzel) in den \(y\)-Koordinaten in der Sekundärstruktur durchgeführt werden. Dies kostet \(\O (\log n)\) Zeit, kann aber jeweils in \(\O (1)\) Zeit nach unten in die relevanten
Kindknoten propagiert werden.
Daher reicht es aus, nur in der Wurzel die Sekundärstruktur als Suchbaum zu speichern und in allen anderen inneren Knoten als sortiertes Array. Die Gesamt-Laufzeit verringert sich zu \(\O (\log n + k)\), weil nur eine
Suche in den \(y\)-Koordinaten durchgeführt werden muss (der Platzaufwand ändert sich nicht).
kd-Bäume
Es gibt auch einen anderen Weg, das mehrdimensionale Problem der Bereichsabfrage zu lösen. Dazu erstellt man zunächst einen kd-Baum.
kd-Baum: Ein kd-Baum für die Punktmenge \(P \subset \real ^2\) ist ein vollständiger binärer Baum, bei dem jeder innere Knoten
entweder ein \(X\)- oder ein \(Y\)-Knoten ist. \(X\)-Knoten enthalten einen \(x\)-Wert, sodass alle Blätter des linken/rechten Teilbaums kleinere/größere \(x\)-Koordinaten haben (analog für
\(Y\)-Knoten). In den Blättern stehen die Punkte aus \(P\) (nicht in den Knoten). Der Baum wird wie folgt konstruiert: Zunächst wählt man den Median \(m_x\) der \(x\)-Koordinaten aller Punkte aus
\(P\). Die Wurzel ist ein \(X\)-Knoten mit dem \(x\)-Schlüssel \(m_x\). Die Gerade \(x = m_x\) teilt \(P\) in zwei Hälften \(P_1\) und \(P_2\) auf. Nun berechnet man den Median \(m_{y,1}\) der
\(y\)-Koordinaten der Punkte aus \(P_1\). Das linke Kind der Wurzel ist ein \(Y\)-Knoten mit dem \(y\)-Schlüssel \(m_{y,1}\). Analog verfährt man mit dem rechten Kind. So wechseln sich in jeder Ebene \(X\)-
und \(Y\)-Knoten ab.
Zeitaufwand für Konstruktion: \(\O (n \log n)\) (Lösung von \(T(n) = n + 2 \cdot T(n/2)\) mit dem Master-Theorem, der erste Summand wird für die Medianberechnung
benötigt)
Platzaufwand: \(\O (n)\) (Baum hat Höhe \(\O (\log n)\))
Man kann zusätzlich jedem inneren Knoten eine Bounding-Box zuordnen, die alle Punkte der Blätter des Teilbaums des inneren Knotens umgibt.
Bereichsabfrage: Für eine Bereichsabfrage \([l, r] \times [u, o]\) traversiert man den Baum von oben nach unten. Wenn die Bounding-Box komplett im Abfragerechteck enthalten ist, gibt man einfach alle
Punkte im Teilbaum aus. Wenn die Bounding-Box disjunkt zum Abfragerechteck ist, dann kann man mit der Traversierung von diesem Teilbaum aufhören. Wenn die Bounding-Box das Abfragerechteck überlappt,
dann untersucht man rekursiv beide Kindknoten.
Der Zeitaufwand ist allerdings i. A. wesentlich höher wie bei Range-Bäumen: Man kann sich Beispiele ausdenken, bei denen das Abfragerechteck keinen Punkt enthält, aber \(\Theta (\sqrt
{n})\) viele „Zellen“ (Bounding-Boxes) schneidet. Man kann jedoch zeigen, dass dies der „worst case“ ist.
Zeitaufwand für Abfrage: \(\O (\sqrt {n} + k)\)
Beweis: Zellen, die disjunkt zum Abfragerechteck sind, können ignoriert werden. Der Zeitaufwand für die Ausgabe der Blätter der vollständig im Abfragerechteck liegenden Zellen ist
\(\O (k)\) nach Konstruktion. Man interessiert sich also nur für die Zellen, die eine Kante des Rechtecks schneiden, z. B. die rechte Kante. Wenn man zeigen kann, dass jede Vertikale \(\O (\sqrt {n})\) Zellen
schneidet, dann folgt die Behauptung, denn andere Arten von Zellen gibt es nicht.
Sei also \(L(n)\) die Anzahl von Zellen (im Unterbaum eines die Vertikale schneidenden \(X\)-Knotens mit \(n\) Blättern), die von der Vertikalen geschnitten werden.
Es gilt \(L(n) = 2 + 2 \cdot L(n/4)\), denn einmal schneidet die Zelle des \(X\)-Knotens selbst die Vertikale und noch einmal oBdA die rechte Teilzelle der Zelle. Nun müssen noch die Unterzellen der zwei
Hälften (oben und unten, enthalten jeweils \(\frac {n}{4}\) Zellen) der rechten Teilzelle gezählt werden. Diese Rekursion kann man dem Master-Theorem nach \(L(n) = \O (\sqrt {n})\)
aufgelöst werden.
Intervall-Bäume
Problem: Gegeben ist eine Menge \(S \subset \P (\real )\) von Intervallen sowie ein Punkt \(q \in \real \). Gesucht sind alle Intervalle \(s \in S\), sodass \(q \in s\) gilt.
Intervall-Baum: Ein Intervall-Baum ist ein balancierter Binärbaum und ist wie folgt rekursiv definiert. Für \(n\) Intervalle in der Menge \(S\) bestimme
den Median \(m\) der \(2n\) Endpunkte. Anschließend unterteile \(S\) auf in \(S = S_L \dcup S_M \dcup S_R\), wobei \(S_L\) und \(S_R\) die Intervalle enthalten, die komplett links bzw. rechts von \(m\) liegen, und \(S_M\) die
Intervalle enthält, die \(m\) enthalten. Erstelle einen Baumknoten und speichere darin \(m\) und die Intervalle aus \(S_M\). Der linke und rechte Teilbaum werden rekursiv mit \(S_L\) und \(S_R\) erstellt.
Dieser Baum ist tatsächlich balanciert, weil \(S_L\) und \(S_R\) jeweils höchstens \(n/2\) Intervalle enthalten (es liegen höchstens \(2n/2 = n\) Endpunkte links von \(m\) und weil jedes Intervall zwei
Endpunkte hat, können höchstens \(n/2\) Intervalle komplett links von \(m\) sein).
Abfrage: Die Abfrage für ein \(q \in \real \) erfolgt rekursiv in einem Pfad von oben nach unten. Wenn für den aktuellen Knoten \(q < m\) gilt, dann wird rekursiv in \(S_L\) nachgeschaut
(\(S_R\) ist irrelevant) und einige Intervalle in \(S_M\) müssen ausgegeben werden. Um dies effizient erledigen zu können, speichere bei der Konstruktion zwei Kopien von \(S_M\) in den Knoten: einmal sortiert
nach linkem und einmal sortiert nach rechtem Endpunkt. Weil \(q < m\) ist, gilt nämlich \(q \in s\) für \(s \in S_M\) genau dann, wenn der linke Endpunkt links von \(q\) liegt. Gehe nun die Intervalle
aufsteigend nach linkem Endpunkt durch und gebe sie aus. Gestoppt wird, wenn der linke Endpunkt rechts von \(q\) liegt. Analog verfährt man, wenn \(q > m\) gilt.
Zeitaufwand für Konstruktion: \(\O (n \log n)\)
Beweis: Die Medianbildung und Aufteilung der Intervalle kostet \(\O (n)\) für jede Ebene des Baums (weil in jeder Ebene höchstens \(n\) Intervalle sind), also \(\O (n \log n)\) insgesamt. Die
Sortierung benötigt \(\O (|S_M| \log |S_M|)\). Weil jedes Intervall in genau einem \(S_M\) vorkommt, ist die Gesamtzeit für alle sortierten Arrays \(\O (n \log n)\).
Zeitaufwand für Abfrage: \(\O (\log n + k)\)
Beweis: Der Abstieg im Baum kostet Zeit \(\O (\log n)\) (der Baum ist balanciert), die effiziente Ausgabe der Intervalle aus \(S_M\) kostet Zeit \(\O (k)\), weil die Arrays sortiert sind.
Platzaufwand: \(\O (n)\)
Beweis: In jedem Knoten wird \(m\) und \(S_M\) (zweimal) gespeichert. Weil die \(S_M\) paarweise disjunkt sind, ist der gesamte Platzaufwand für die \(S_M\) gleich \(\O (n)\). Der Baum an sich ist ein
balancierter Binärbaum mit \(\O (\log n)\) Höhe und \(\O (n)\)-vielen Knoten, wobei außer \(S_M\) pro Knoten nur \(\O (1)\) Platz benötigt wird. Damit ist der Gesamt-Platzaufwand \(\O (n)\).
Segment-Bäume
Es ist nicht klar, wie man Intervallbäume auf mehrere Dimensionen verallgemeinert, denn die \(S_M\) sind durch die Sortierung schon strukturiert. Dazu wird im Folgenden das eindimensionale Problem durch sog.
Segment-Bäume gelöst. Diese können wie bei Range-Bäumen einfach verschachtelt werden.
Segment-Baum: Ein Segment-Baum ist ein balancierter binärer Suchbaum und ist wie folgt definiert. Betrachte die gegebene Menge \(S \subset \P (\real )\)
von \(n\) Intervallen. Die Endpunkte der Intervalle unterteilen die reelle Achse in \(\le 2n + 1\) Abschnitte, die sog. elementaren Intervalle. Erstelle nun einen binären
Suchbaum über die elementaren Intervalle, wobei die elementaren Intervalle in den Blättern stehen und in jedem Knoten \(v\) ein natürliches Intervall
\(I(v)\) gespeichert ist, das als Vereinigung der elementaren Intervalle des Teilbaums unter \(v\) definiert ist. Außerdem speichert jeder Knoten \(v\) eine Liste \(S(v)\) von bestimmten Intervallen \(s \in S\). Ein Intervall \(s
\in S\) wird in \(S(v)\) gespeichert, falls \(I(v) \subset s\), aber \(I(\parent (v)) \not \subset s\).
Jede Ebene des Baums definiert eine Partition der reellen Achse, die zur Wurzel hin immer gröber wird.
Abfrage: Für eine Abfrage suche zunächst \(q \in \real \) im Suchbaum (einfacher Pfad von der Wurzel nach unten), wobei man jeweils zu dem Kind \(v\) wechselt, dessen natürliches
Intervall \(I(v)\) den Punkt \(q\) enthält. Die Ausgabe ist die Menge von Intervallen \(I(v)\) der Knoten auf dem Suchpfad (Ausgabe erfolgt in \(\O (\log n)\)-vielen Paketen).
Zeitaufwand für Konstruktion: \(\O (n \log n)\)
Zeitaufwand für Abfrage: \(\O (\log n + k)\)
Platzaufwand: \(\O (n \log n)\)
Beweis: Sei \(s \in S\) fest. Dann wird auf jeder Ebene \(s\) jeweils in höchstens zwei Knoten gespeichert. Würde es in drei Knoten \(v_1, v_2, v_3\) gespeichert werden, dann müssten
zwei der Knoten einen gemeinsamen Vater haben, also z. B. \(v := \parent (v_1) = \parent (v_2)\). Dann wäre aber \(I(v_1), I(v_2) \subset s\), d. h. \(I(v) = I(v_1) \cup I(v_2)
\subset s\), ein Widerspruch zu \(I(v) = I(\parent (v_1)) \not \subset s\). Daher wird jedes Intervall \(\O (\log n)\) Mal gespeichert und der Platzverbrauch ist \(\O (n \log n)\).
Priority Search Trees (Treaps)
Bei kd-Bäumen wurden die \(x\)- und \(y\)-Dimensionen miteinander verwoben, was zwar zur einer Datenstruktur mit Platzverbrauch \(\O (n)\) geführt hat, aber zu einem schlechten Abfrage-Zeitaufwand.
PSTs folgen demselben Prinzip mit einem besseren Abfrage-Zeitaufwand von \(\O (\log n + k\)). Allerdings können sie nur etwas speziellere Anfragen beantworten.
Problem: Gegeben sind \(n\) Pkt.e \(P = \{a_1, \dotsc , a_n\} \subset \real ^2\) sowie ein Rechteck \([l, r] \times [-\infty , o]\), das in einer Dimension halboffen ist. Gesucht sind alle Punkte, die in
diesem Rechteck liegen.
Priority Search Tree (PST): Ein Priority Search Tree (PST) ist ein Treap, eine Mischung von binärem Suchbaum
(engl. tree) und Heap, der wie folgt konstruiert wird. Jeder Knoten speichert zwei Schlüssel, einen \(X\)- und einen \(Y\)-Schlüssel.
Berechne das \(y\)-Minimum von \(P\) und speichere den entsprechenden Punkt \(p_1\) als \(Y\)-Schlüssel des Knotens.
Berechne den \(x\)-Median von \(P \setminus \{p_1\}\) und speichere den entsprechenden \(x\)-Wert als \(X\)-Schlüssel des Knotens.
Teile \(P \setminus \{p_1\}\) entsprechend des Medians in zwei Mengen mit kleinerer bzw. größerer \(x\)-Koordinate auf und wiederhole das Verfahren rekursiv.
Der Baum ist zum einen ein binärer Suchbaum über den \(x\)-Koordinaten mit Tiefe \(\O (\log n)\) und zum anderen ein Min-Heap über den \(y\)-Koordinaten.
Abfrage:
Suche nach \(l\) und \(r\) (PST als eindim. Suchbaum über den \(x\)-Koordinaten).
Exploriere Teilbäume nach „innen“ nach Punkten mit \(y\)-Koordinate \(\le o\)
(PST als Min-Heap über den \(y\)-Koordinaten).
Bei einem Min-Heap ist es möglich, alle Elemente \(\le o\) in der Zeit \(\O (k)\) auszugeben, wenn \(k\) die Ausgabegröße ist.
Zeitaufwand für Konstruktion: \(\O (n \log n)\)
Zeitaufwand für Abfrage: \(\O (\log n + k)\)
Platzaufwand: \(\O (n)\)
Zusammenfassung der Suchstrukturen
|
Range-Baum
|
Intervall-Baum
|
Segment-Baum
|
PST (Treap)
|
verarbeitete Eingabe
|
Punktmenge
\(P \subset \real \)
|
Intervallmenge
\(S \subset \P (\real )\)
|
Intervallmenge
\(S \subset \P (\real )\)
|
Punktmenge
\(P \subset \real ^2\)
|
Abfrageobjekt
|
Intervall \([l, r]\)
|
Punkt \(q \in \real \)
|
Punkt \(q \in \real \)
|
halboff. Rechteck \(R\)
\(:= [l, r] \times [-\infty , o]\)
|
Abfrageergebnis
|
\(p \in P\) mit \(p \in [l, r]\)
|
\(s \in S\) mit \(s \ni q\)
|
\(s \in S\) mit \(s \ni q\)
|
\(p \in P\) mit \(p \in R\)
|
Konstruktionszeit
|
\(\O (n \log n)\) |
Abfragezeit
|
\(\O (\log n + k)\) |
Platz
|
\(\O (n)\)
|
\(\O (n)\)
|
\(\O (n \log n)\)
|
\(\O (n)\)
|
Ergebnis in Blöcken
(stöpselbar)
|
ja
|
(nein)
|
ja
|
nein
|
|
|
|
|
|