Splay-puu on itsesäätyvä binäärihakupuun tietorakenne, mikä tarkoittaa, että puurakennetta säädetään dynaamisesti käytettyjen tai lisättyjen elementtien perusteella. Toisin sanoen puu järjestää itsensä automaattisesti uudelleen niin, että usein käytetyt tai lisätyt elementit tulevat lähemmäksi juurisolmua.
- Splay-puun esittelivät ensimmäisen kerran Daniel Dominic Sleator ja Robert Endre Tarjan vuonna 1985. Siinä on yksinkertainen ja tehokas toteutus, jonka avulla se voi suorittaa haku-, lisäys- ja poistotoimintoja O(log n) -kuormitetussa aikakompleksisuudessa, jossa n on elementtien lukumäärä puussa.
- Splay-puiden perusideana on tuoda viimeksi käytetty tai lisätty elementti puun juurelle suorittamalla puun kiertosarja, jota kutsutaan splayingiksi. Splaying on prosessi, jossa puu rakennetaan uudelleen tekemällä viimeksi käytetty tai lisätty elementti uudeksi juureksi ja siirtämällä loput solmut vähitellen lähemmäs juuria.
- Splay-puut ovat käytännössä erittäin tehokkaita itsesäätyvän luonteensa vuoksi, mikä vähentää usein käytettyjen elementtien kokonaiskäyttöaikaa. Tämä tekee niistä hyvän valinnan sovelluksille, jotka vaativat nopeita ja dynaamisia tietorakenteita, kuten välimuistijärjestelmiä, tietojen pakkausta ja verkon reititysalgoritmeja.
- Levityspuiden suurin haittapuoli on kuitenkin se, että ne eivät takaa tasapainoista puurakennetta, mikä voi johtaa suorituskyvyn heikkenemiseen pahimmassa tapauksessa. Levityspuut eivät myöskään sovellu sovelluksiin, jotka vaativat taattua huonoimman tapauksen suorituskykyä, kuten reaaliaikaiset järjestelmät tai turvallisuuskriittiset järjestelmät.
Kaiken kaikkiaan splay-puut ovat tehokas ja monipuolinen tietorakenne, joka tarjoaa nopean ja tehokkaan pääsyn usein käytettyihin tai lisättyihin elementteihin. Niitä käytetään laajasti erilaisissa sovelluksissa ja ne tarjoavat erinomaisen kompromissin suorituskyvyn ja yksinkertaisuuden välillä.
Splay-puu on itsetasapainottava binäärihakupuu, joka on suunniteltu tehokkaaseen pääsyyn tietoelementteihin niiden avainarvojen perusteella.
- Splay-puun tärkein ominaisuus on, että joka kerta kun elementtiä käytetään, se siirretään puun juureen, mikä luo tasapainoisemman rakenteen myöhempiä käyttöoikeuksia varten.
- Splay-puille on ominaista niiden rotaatioiden käyttö, jotka ovat puun paikallisia muunnoksia, jotka muuttavat sen muotoa, mutta säilyttävät elementtien järjestyksen.
- Rotaatioita käytetään tuomaan käytetty elementti puun juurelle ja myös tasapainottamaan puu uudelleen, jos se epätasapainoinen useiden käyttökertojen jälkeen.
Toiminnot splay-puussa:
- Lisäys: Jos haluat lisätä uuden elementin puuhun, aloita suorittamalla tavallinen binäärihakupuun lisäys. Käytä sitten pyörityksiä tuodaksesi juuri lisätyn elementin puun juureen.
- Poistaminen : Jos haluat poistaa elementin puusta, etsi se ensin käyttämällä binaarihakua. Sitten, jos elementillä ei ole lapsia, poista se. Jos sillä on yksi lapsi, ylennä se asemaansa puussa. Jos sillä on kaksi alaluokkaa, etsi elementin seuraaja (pienin elementti sen oikeanpuoleisesta alipuusta), vaihda sen avain poistettavan elementin kanssa ja poista sen sijaan seuraaja.
- Hae : Jos haluat etsiä elementtiä puusta, aloita suorittamalla binäärihakupuuhaku. Jos elementti löytyy, käännä se puun juureen. Jos sitä ei löydy, käytä kiertoja haussa viimeksi vieraillulle solmulle, josta tulee uusi juuri.
- Kierto : Splay-puussa käytetyt kierrokset ovat joko sik- tai sik-zig-kiertoja. Zig-kiertoa käytetään tuomaan solmu juurille, kun taas Zig-Zig-kiertoa käytetään puun tasapainottamiseen sen jälkeen, kun saman alipuun elementteihin on käytetty useita.
Tässä on askel askeleelta selitys kiertotoiminnoista:
- Zig-kierto : Jos solmulla on oikea lapsi, suorita oikea kierto tuodaksesi sen juureen. Jos siinä on vasen lapsi, käännä vasemmalle.
- Zig-Zig-kierto: Jos solmulla on lapsenlapsi, joka on myös sen lapsen oikea tai vasen lapsi, suorita kaksoiskierto puun tasapainottamiseksi. Jos esimerkiksi solmulla on oikea lapsi ja oikealla lapsella vasen lapsi, suorita kierto oikealta vasemmalle. Jos solmussa on vasen lapsi ja vasemmalla lapsella oikea lapsi, suorita kierto vasemmalta oikealle.
- Huomautus: Erityiset toteutustiedot, mukaan lukien tarkat käytetyt kierrokset, voivat vaihdella leikkauspuun tarkan muodon mukaan.
Rotaatiot Splay Treessä
- Zig-kierto
- Zag Rotation
- Zig – Zig Rotation
- Zag – Zag Rotation
- Zig – Zag Rotation
- Zag – Zig-kierto
1) Zig-kierto:
Zig Rotation splay-puissa toimii samalla tavalla kuin yksi oikea kierto AVL-puun rotaatioissa. Tämä kierto johtaa siihen, että solmut siirtyvät yhden sijainnin oikealle nykyisestä sijainnistaan. Harkitse esimerkiksi seuraavaa skenaariota:

Zig-kierto (yksi kierto)
2) Zag-kierto:
Zag Rotation splay-puissa toimii samalla tavalla kuin yksittäinen kierto vasemmalle AVL-puun rotaatioissa. Tämän kierron aikana solmut siirtyvät yhden sijainnin vasemmalle nykyisestä sijainnistaan. Harkitse esimerkiksi seuraavaa kuvaa:
python alustusluettelo

Zag Rotation (yksi kierto vasemmalle)
3) Zig-Zig-kierto:
Zig-Zig Rotation splay-puissa on kaksinkertainen zig-kierto. Tämä kierto johtaa siihen, että solmut siirtyvät kaksi paikkaa oikealle nykyisestä sijainnistaan. Katso seuraava esimerkki ymmärtääksesi paremmin:
jos muuten lauseke java

Zig-Zig-kierto (kaksoiskierto oikealle)
4) Zag-Zag-kierto:
Splay-puissa Zag-Zag Rotation on kaksoissak-kierto. Tämä kierto saa solmut siirtymään kaksi paikkaa vasemmalle nykyisestä sijainnistaan. Esimerkiksi:

Zag-Zag-kierto (kaksoiskierto vasemmalle)
5) Siksak-kierto:
Zig-Zag Rotation splay-puissa on yhdistelmä sik-kiertoa, jota seuraa zig-kierto. Tämän kierron seurauksena solmut siirtyvät yhden sijainnin oikealle ja sitten yhden sijainnin vasemmalle nykyisestä sijainnistaan. Seuraava kuva tarjoaa visuaalisen esityksen tästä konseptista:

Zig-Zag-kierto
6) Zag-Zig-kierto:
Zag-Zig Rotation splay-puissa on sarja zig-kiertoja, joita seuraa sik-kierto. Tämä johtaa siihen, että solmut siirtyvät yhden sijainnin vasemmalle, minkä jälkeen siirtyvät yhden sijainnin oikealle nykyisestä sijainnistaan. Seuraava kuva tarjoaa visuaalisen esityksen tästä konseptista:

Zag-Zig-kierto
Alla on C++-koodi rotaatioiden toteuttamiseksi Splay-puussa:
C++ #include using namespace std; struct Node { int key; Node *left, *right; }; Node* newNode(int key) { Node* node = new Node(); node->avain = avain; solmu->vasen = solmu->oikea = nullptr; paluusolmu; } Solmu* oikealleKierrä(Solmu* x) { Solmu* y = x->vasen; x->vasen = y->oikea; y->oikea = x; palauttaa y; } Solmu* vasenKierrä(Solmu* x) { Solmu* y = x->oikea; x->oikea = y->vasen; y->vasen = x; palauttaa y; } Solmu* splay(Solmu* juuri, int-avain) { if (juuri == nullptr || root->avain == avain) palauttaa juuri; if (juuri->avain> avain) { if (root->left == nullptr) return root; if (juuri->vasen->näppäin> avain) { juuri->vasen->vasen = splay(juuri->vasen->vasen, näppäin); juuri = oikeaKierrä(juuri); } else if (juuri->vasen->näppäin< key) { root->vasen->oikea = splay(juuri->vasen->oikea, näppäin); if (juuri->vasen->oikea != nullptr) root->left = vasenKierrä(juuri->vasen); } return (juuri->vasen == nullptr) ? juuri : rightRotate(juuri); } else { if (root->right == nullptr) return root; if (juuri->oikea->näppäin> avain) { juuri->oikea->vasen = splay(juuri->oikea->vasen, avain); if (juuri->oikea->vasen != nullptr) root->right = oikeaKierrä(juuri->oikea); } else if (root->right->key< key) { root->oikea->oikea = splay(juuri->oikea->oikea, näppäin); juuri = vasenKierrä(juuri); } return (root->right == nullptr) ? juuri : vasenKierrä(juuri); } } Solmu* insert(Solmu* juuri, int avain) { if (juuri == nullptr) return newSolmu(avain); juuri = splay(juuri, avain); if (root->key == avain) palauttaa juuren; Solmu* solmu = uusiSolmu(avain); if (juuri->avain> avain) { solmu->oikea = juuri; solmu->vasen = juuri->vasen; juuri->vasen = nullptr; } else { solmu->vasen = juuri; solmu->oikea = juuri->oikea; root->right = nullptr; } paluusolmu; } void preOrder(Solmu* solmu) { if (solmu != nullptr) { cout<< node->avain<< ' '; preOrder(node->vasen); preOrder(solmu->oikea); } } int main() { Solmu* root = nullptr; juuri = insert(juuri, 100); juuri = insert(juuri, 50); juuri = insert(juuri, 200); juuri = insert(juuri, 40); juuri = insert(juuri, 60); cout<< 'Preorder traversal of the modified Splay tree:' << endl; preOrder(root); return 0; }> Java // Java Program for the above approach class Node { public int key; public Node left, right; } class SplayTree { static Node newNode(int key) { Node node = new Node(); node.key = key; node.left = node.right = null; return node; } static Node rightRotate(Node x) { Node y = x.left; x.left = y.right; y.right = x; return y; } static Node leftRotate(Node x) { Node y = x.right; x.right = y.left; y.left = x; return y; } static Node splay(Node root, int key) { if (root == null || root.key == key) return root; if (root.key>avain) { if (root.left == null) return root; if (root.left.key> avain) { root.left.left = splay(root.left.left, key); juuri = oikeaKierrä(juuri); } else if (root.left.key< key) { root.left.right = splay(root.left.right, key); if (root.left.right != null) root.left = leftRotate(root.left); } return (root.left == null) ? root : rightRotate(root); } else { if (root.right == null) return root; if (root.right.key>avain) { juuri.oikea.vasen = splay(root.right.left, key); if (juuri.oikea.vasen != null) root.right = rightRotate(root.right); } else if (root.right.key< key) { root.right.right = splay(root.right.right, key); root = leftRotate(root); } return (root.right == null) ? root : leftRotate(root); } } static Node insert(Node root, int key) { if (root == null) return newNode(key); root = splay(root, key); if (root.key == key) return root; Node node = newNode(key); if (root.key>avain) { solmu.oikea = juuri; solmu.vasen = root.left; root.left = null; } else { solmu.vasen = juuri; solmu.oikea = juuri.oikea; root.right = null; } paluusolmu; } static void preOrder(Solmusolmu) { if (solmu != null) { System.out.println(); System.out.print(solmu.avain + ' '); ennakkotilaus(solmu.vasen); ennakkotilaus(solmu.oikea); } } public static void main(String[] args) { Solmun juuri = null; juuri = insert(juuri, 100); juuri = insert(juuri, 50); juuri = insert(juuri, 200); juuri = insert(juuri, 40); juuri = insert(juuri, 60); System.out.println('Muokatun Splay-puun ennakkotilaus:'); preOrder(root); } } // Tämän koodin on tuottanut princekumaras> Python 3 class Node: def __init__(self, key): self.key = key self.left = None self.right = None def new_node(key): return Node(key) def right_rotate(x): y = x.left x.left = y.right y.right = x return y def left_rotate(x): y = x.right x.right = y.left y.left = x return y def splay(root, key): if root is None : return new_node(key) if root.key == key: return root if root.key>avain: jos root.left on Ei mitään: palauta root if root.left.key> avain: root.left.left = splay(root.left.left, key) root = right_rotate(root) elif root.left.key< key: root.left.right = splay(root.left.right, key) if root.left.right: root.left = left_rotate(root.left) return root.left if root.left is None else right_rotate(root) else: if root.right is None: return root if root.right.key>avain: root.right.left = splay(root.right.left, key) if root.right.left: root.right = right_rotate(root.right) elif root.right.key< key: root.right.right = splay(root.right.right, key) root = left_rotate(root) return root.right if root.right is None else left_rotate(root) def insert(root, key): if root is None: return new_node(key) root = splay(root, key) if root.key == key: return root node = new_node(key) if root.key>avain: node.right = root node.left = root.left root.left = Ei mitään muuta: node.left = juurisolmu.right = root.right root.right = Ei mitään palauttaa solmun def pre_order(node): if node: tulosta (solmu.avain, end=' ') pre_order(node.left) pre_order(node.right) if __name__ == '__main__': root = Ei mitään root = insert(juuri, 100) root = insert(root , 50) root = insert(juuri, 200) juuri = insert(juuri, 40) juuri = insert(juuri, 60) print('Muokatun Splay-puun ennakkotilaus:') pre_order(root)> C# // C# program for the above approach using System; class Node { public int key; public Node left, right; } class SplayTree { static Node newNode(int key) { Node node = new Node(); node.key = key; node.left = node.right = null; return node; } static Node rightRotate(Node x) { Node y = x.left; x.left = y.right; y.right = x; return y; } static Node leftRotate(Node x) { Node y = x.right; x.right = y.left; y.left = x; return y; } static Node splay(Node root, int key) { if (root == null || root.key == key) return root; if (root.key>avain) { if (root.left == null) return root; if (root.left.key> avain) { root.left.left = splay(root.left.left, key); juuri = oikeaKierrä(juuri); } else if (root.left.key< key) { root.left.right = splay(root.left.right, key); if (root.left.right != null) root.left = leftRotate(root.left); } return (root.left == null) ? root : rightRotate(root); } else { if (root.right == null) return root; if (root.right.key>avain) { juuri.oikea.vasen = splay(root.right.left, key); if (juuri.oikea.vasen != null) root.right = rightRotate(root.right); } else if (root.right.key< key) { root.right.right = splay(root.right.right, key); root = leftRotate(root); } return (root.right == null) ? root : leftRotate(root); } } static Node insert(Node root, int key) { if (root == null) return newNode(key); root = splay(root, key); if (root.key == key) return root; Node node = newNode(key); if (root.key>avain) { solmu.oikea = juuri; solmu.vasen = root.left; root.left = null; } else { solmu.vasen = juuri; solmu.oikea = juuri.oikea; root.right = null; } paluusolmu; } static void preOrder(Solmusolmu) { if (solmu != null) { Console.Write(solmu.avain + ' '); ennakkotilaus(solmu.vasen); ennakkotilaus(solmu.oikea); } } public static void Main(merkkijono[] args) { Solmun juuri = null; juuri = insert(juuri, 100); juuri = insert(juuri, 50); juuri = insert(juuri, 200); juuri = insert(juuri, 40); juuri = insert(juuri, 60); Console.WriteLine('Ennakkotilaa muokatun Splay-puun läpikulku:'); preOrder(root); } } // Tämän koodin on antanut prinssi Kumar>>Javascript>
Lähtö Epätasapainoiset puut: Kierrepuut voivat muuttua epätasapainoisiksi ja tehottomia, jos puuta käännetään toistuvasti samaan suuntaan. Muistin käyttö: Splay-puut voivat käyttää paljon muistia muihin tietorakenteisiin verrattuna, koska jokainen solmu sisältää lisätietoa. Monimutkaisuus: Splay-puilla voi olla aika monimutkaisia perustoimintoja, kuten lisäämistä ja poistamista, koska puut on järjestettävä uudelleen jokaisen toimenpiteen jälkeen. Uudelleenjärjestelykulut: Jokaisessa toimenpiteessä vaadittava leikkaustoiminto voi olla aikaa vievä ja aiheuttaa suuria yleiskustannuksia. Rajoitettu käyttötapaukset : Splay-puut eivät sovellu kaikkiin tietorakenteisiin, ja niiden käyttötapaukset ovat rajalliset, koska ne eivät käsittele päällekkäisiä avaimia tehokkaasti. Splay-puun sovellukset:
- Välimuisti : Splay-puita voidaan käyttää välimuistin hallinnan toteuttamiseen, jossa useimmin käytetyt kohteet siirretään puun yläosaan nopeuttamaan pääsyä.
- Tietokannan indeksointi : Splay-puita voidaan käyttää tietokantojen indeksointiin tiedonhaun ja -haun nopeuttamiseksi.
- Tiedostojärjestelmät : Splay-puita voidaan käyttää tiedostojärjestelmän metatietojen, kuten varaustaulukon, hakemistorakenteen ja tiedostomääritteiden, tallentamiseen.
- Tietojen pakkaus: Splay-puita voidaan käyttää tietojen pakkaamiseen tunnistamalla ja koodaamalla toistuvia kuvioita.
- Tekstinkäsittely : Splay-puita voidaan käyttää tekstinkäsittelysovelluksissa, kuten oikeinkirjoituksen tarkistuksissa, joissa sanat tallennetaan splay-puuhun nopeaa hakua ja hakua varten.
- Graafialgoritmit: Splay-puita voidaan käyttää kuvaajaalgoritmien toteuttamiseen, kuten lyhimmän polun löytämiseen painotetusta graafista.
- Online-pelaaminen: Pelipuita voidaan käyttää online-peleissä korkeiden tulosten, tulostaulukoiden ja pelaajatilastojen tallentamiseen ja hallintaan.
Toki tässä on joitain splay-puiden etuja ja haittoja sekä joitain suositeltuja kirjoja, joiden avulla voit oppia lisää aiheesta:
gigatavu vs megatavu
Splay Treesin edut:
Splay-puut ovat poistaneet monien toimintojen aikakompleksisuuden O(log n), mikä tekee niistä joissakin tapauksissa nopeampia kuin monet muut tasapainotetut puutietorakenteet.
Splay-puut ovat itsesäätyviä, mikä tarkoittaa, että ne tasapainottavat itsensä automaattisesti, kun kohteita asetetaan ja poistetaan. Tämä voi auttaa välttämään suorituskyvyn heikkenemistä, joka voi tapahtua, kun puu muuttuu epätasapainoiseksi.
Splay-puiden haitat:
Splay-puiden aikakompleksisuus voi olla pahimmassa tapauksessa O(n) joissakin operaatioissa, mikä tekee niistä vähemmän ennustettavia kuin muut tasapainotetut puutietorakenteet, kuten AVL-puut tai punamustat puut.
Splay-puut eivät välttämättä sovellu tiettyihin sovelluksiin, joissa vaaditaan ennustettavaa suorituskykyä.
Suositellut kirjat Splay Treesistä:
Tietorakenteet ja algoritmianalyysi Javassa, kirjoittanut Mark Allen Weiss
Johdatus algoritmeihin: Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest ja Clifford Stein
Tietorakenteet ja algoritmit C++:ssa Michael T. Goodrich ja Roberto Tamassia
Johtopäätös:
Yhteenvetona voidaan todeta, että Splay Trees ovat dynaaminen itsetasapainottava binäärihakupuutietorakenne, joka tarjoaa tehokkaan tavan etsiä, lisätä ja poistaa elementtejä. Ne eroavat perinteisistä tasapainotetuista binäärihakupuista, kuten AVL- ja Red-Black-puista, koska ne järjestävät puun uudelleen jokaisen toiminnon jälkeen tuodakseen äskettäin avatun solmun juureen. Tämä auttaa vähentämään puun korkeutta ja nopeuttaa toimintaa. Splay Trees ovat erittäin joustavia ja niitä voidaan mukauttaa erilaisiin käyttötarkoituksiin. Vaikka niillä voi olla korkeampi kiertokulu, yksinkertaisuus ja monipuolisuus tekevät niistä hyödyllisiä työkaluja monenlaisten ongelmien ratkaisemiseen.