Splay-дерево

Расширяющееся дерево
Тип Дерево
Год изобретения 1985
Автор Дэниел Слитор и Роберт Андре Тарьян
Сложность в О-символике
В среднем В худшем случае
Расход памяти O(n) O(n)
Поиск O(log n) O(log n)
Вставка O(log n) O(log n)
Удаление O(log n) O(log n)

Расширяющееся (англ. splay tree) или косое дерево является двоичным деревом поиска, в котором поддерживается свойство сбалансированности. Это дерево принадлежит классу «саморегулирующихся деревьев», которые поддерживают необходимый баланс ветвления дерева, чтобы обеспечить выполнение операций поиска, добавления и удаления за логарифмическое время от числа хранимых элементов. Это реализуется без использования каких-либо дополнительных полей в узлах дерева (как, например, в Красно-чёрных деревьях или АВЛ-деревьях, где в вершинах хранится, соответственно, цвет вершины и глубина поддерева). Вместо этого «расширяющие операции» (splay operation), частью которых являются вращения, выполняются при каждом обращении к дереву.

Учётная стоимость в расчёте на одну операцию с деревом составляет .

Расширяющееся дерево придумали Роберт Тарьян и Даниель Слейтор в 1983 году.

Операции

Splay (расширение)

Основная операция дерева. Заключается в перемещении вершины в корень при помощи последовательного выполнения трёх операций: Zig, Zig-Zig и Zig-Zag. Обозначим вершину, которую хотим переместить в корень за x, её родителя — p, а родителя p (если существует) — g.

Zig: выполняется, когда p является корнем. Дерево поворачивается по ребру между x и p. Существует лишь для разбора крайнего случая и выполняется только один раз в конце, когда изначальная глубина x была нечётна.

Zig-Zig: выполняется, когда и x, и p являются левыми (или правыми) сыновьями. Дерево поворачивается по ребру между g и p, а потом — по ребру между p и x.

Zig-Zag: выполняется, когда x является правым сыном, а p — левым (или наоборот). Дерево поворачивается по ребру между p и x, а затем — по ребру между x и g.

Search (поиск элемента)

Поиск выполняется как в обычном двоичном дереве поиска. При нахождении элемента запускаем Splay для него.

Insert (добавление элемента)

Запускаем Split() от добавляемого элемента (см Split(), напоминание: в нём используется ближайший больший либо равный элемент существующего дерева) и подвешиваем получившиеся деревья за элемент к добавлению.

Delete (удаление элемента)

Находим элемент в дереве, делаем Splay для него, делаем текущим деревом Merge его детей.

Merge (объединение двух деревьев)

Для слияния деревьев T1 и T2, в которых все ключи T1 меньше ключей в T2, делаем Splay для максимального элемента T1, тогда у корня T1 не будет правого ребенка. После этого делаем T2 правым ребенком T1.

Split (разделение дерева на две части)

Для разделения дерева по значению x найдем наименьший элемент, больший или равный x, и сделаем для него Splay. После этого отсоединяем от корня левого ребёнка и возвращаем 2 получившихся дерева.

Реализация

Одной из реализаций расширяющегося дерева может послужить реализация, использующая 3 указателя в каждой вершине: указатель на правого и левого сыновей, а также на родителя. Это позволяет избежать рекурсивной реализации, что, в свою очередь, повлечет экономию памяти. Минусом в данном случае выступает большее количество присваиваний для обновления указателей, что может сказаться на конечной производительности.

Ниже представлена реализация расширяющегося дерева, использующая по 3 указателя в каждом узле. Также, в данной реализации операция Splay используется во всех основных операциях, выполняемых над деревом — при вставке, удалении и поиске для достижения лучшей сбалансированности дерева.

#ifndef SPLAYTREE_H
#define SPLAYTREE_H

template<typename T> class SplayTree {
private:
    struct SplayNode {
        Node * leftChild;
        Node * rightChild
        Node * parent;
        T data;

        Node (const T & key = T()) 
        : leftChild(nullptr), rightChild(nullptr), parent(nullptr), key(key) {}

        ~Node () {
                delete leftChild;
                delete rightChild;
        }
    } * root;

private:
    SplayNode * _Successor(SplayNode * localRoot) const {
        SplayNode * successor = localRoot;

        if (successor->rightChild != nullptr) {
            successor = _Minimum(successor->rightChild);
        } else {
            while (successor != root
                    || successor != successor->parent->leftChild) {
                successor = successor->parent;
            }
        }

        return successor;
    }

    SplayNode * _Predecessor(SplayNode * localRoot) const {
        SplayNode * predecessor = localRoot;

        if (predecessor->leftChild != nullptr) {
            predecessor = _Maximum(predecessor->leftChild);
        } else {
            while (predecessor != root
                   || predecessor != predecessor->parent->rightChild) {
                predecessor = predecessor->parent;
            }
        }

        return predecessor;
    }

    SplayNode * _Minimum(SplayNode * localRoot) const {
        SplayNode * minimum = localRoot;

        while (minimum->leftChild != nullptr) 
            minimum = minimum->leftChild;
        
        return minimum;
    }

    SplayNode * _Maximum(SplayNode * localRoot) const {
        SplayNode * maximum = localRoot;

        while (maximum->rightChild != nullptr) 
            maximum = maximum->rightChild;

        return maximum;
    }

    SplayNode * _Search(const T & key) {
        SplayNode * searchedElement = root;

        while (searchedElement != nullptr) {
            if (searchedElement->data < key) 
                searchedElement = searchedElement->rightChild;
            else if (key < searchedElement->data) 
                searchedElement = searchedElement->leftChild;
            else if (searchedElement->data == key) {
                _Splay(searchedElement);
                return searchedElement;
            }
        }

        return nullptr;
    }

    void _LeftRotate(SplayNode * localRoot) {
        SplayNode * rightChild = localRoot->rightChild;

        localRoot->rightChild = rightChild->leftChild;
        if (rightChild->leftChild != nullptr) 
            rightChild->leftChild->parent = localRoot;

        _Transplant(localRoot, rightChild);

        rightChild->leftChild = localRoot;
        rightChild->leftChild->parent = rightChild;
    }

    void _RightRotate(SplayNode * localRoot) {
        SplayNode * leftChild = localRoot->leftChild;

        localRoot->leftChild = leftChild->rightChild;
        if (leftChild->rightChild != nullptr) 
            leftChild->rightChild->parent = localRoot;

        _Transplant(localRoot, leftChild);

        leftChild->rightChild = localRoot;
        leftChild->rightChild->parent = leftChild;
    }

    void _Transplant(SplayNode * localParent, SplayNode * localChild) {
        if (localParent->parent == nullptr) 
            root = localChild;
        else if (localParent == localParent->parent->leftChild) 
            localParent->parent->leftChild = localChild;
        else if (localParent == localParent->parent->rightChild) 
            localParent->parent->rightChild = localChild;

        if (localChild != nullptr)
            localChild->parent = localParent->parent;
    }

    void _Splay(SplayNode * pivotElement) {
        while (pivotElement != root) {
            if (pivotElement->parent == root) {

                if (pivotElement == pivotElement->parent->leftChild) {
                    _RightRotate(pivotElement->parent);
                } else if (pivotElement == pivotElement->parent->rightChild) {
                    _LeftRotate(pivotElement->parent);
                }
            } else {
                // Zig-Zig step.
                if (pivotElement == pivotElement->parent->leftChild &&
                    pivotElement->parent == pivotElement->parent->parent->leftChild) {

                    _RightRotate(pivotElement->parent->parent);
                    _RightRotate(pivotElement->parent);

                } else if (pivotElement == pivotElement->parent->rightChild &&
                           pivotElement->parent == pivotElement->parent->parent->rightChild) {

                    _LeftRotate(pivotElement->parent->parent);
                    _LeftRotate(pivotElement->parent);
                }
                // Zig-Zag step.
                else if (pivotElement == pivotElement->parent->rightChild &&
                    pivotElement->parent == pivotElement->parent->parent->leftChild) {

                    _LeftRotate(pivotElement->parent);
                    _RightRotate(pivotElement->parent);

                } else if (pivotElement == pivotElement->parent->leftChild &&
                           pivotElement->parent == pivotElement->parent->parent->rightChild) {

                    _RightRotate(pivotElement->parent);
                    _LeftRotate(pivotElement->parent);
                }
            }
        }
    }
    
public:
    SplayTree() { root = nullptr; }

    virtual ~SplayTree() { delete root; }

    void Insert(const T & key) {
        SplayNode * preInsertPlace = nullptr;
        SplayNode * insertPlace = root;

        while (insertPlace != nullptr) {
            preInsertPlace = insertPlace;

            if (insertPlace->data() < key) 
                insertPlace = insertPlace->rightChild;
            else if (key <= insertPlace->data) 
                insertPlace = insertPlace->leftChild;
        }

        SplayNode * insertElement = new SplayNode(key);
        insertElement->parent = preInsertPlace;

        if (preInsertPlace == nullptr) 
            root = insertElement;
        else if (preInsertPlace->data < insertElement->data) 
            preInsertPlace->rightChild = insertElement;
        else if (insertElement->data <= preInsertPlace->data) 
            preInsertPlace->leftChild = insertElement;

        _Splay(insertElement);
    }

    void Remove(const T & key) {
        SplayNode * removeElement = _Search(key);

        if (removeElement != nullptr) {
            if (removeElement->rightChild == nullptr) 
                _Transplant(removeElement, removeElement->leftChild);
            else if (removeElement->leftChild == nullptr) 
                _Transplant(removeElement, removeElement->rightChild);
            else {
                SplayNode * newLocalRoot = _Minimum(removeElement->rightChild);

                if (newLocalRoot->parent != removeElement) {

                    _Transplant(newLocalRoot, newLocalRoot->rightChild);

                    newLocalRoot->rightChild = removeElement->rightChild;
                    newLocalRoot->rightChild->parent = newLocalRoot;
                }

                _Transplant(removeElement, newLocalRoot);

                newLocalRoot->leftChild = removeElement->leftChild;
                newLocalRoot->leftChild->parent = newLocalRoot;

                _Splay(newLocalRoot);
            }

            delete removeElement;
        }
    }

    bool Search(const T &key) { return _Search(key) != nullptr; }

    bool isEmpty() const { return root == nullptr; }

    T Successor(const T & key) {
        if (_Successor(_Search(key)) != nullptr) {
            return _Successor(_Search(key))->getValue();
        } else {
            return -1;
        }
    }

    T Predecessor(const T & key) {
        if (_Predecessor(_Search(key)) != nullptr) {
            return _Predecessor(_Search(key))->getValue();
        } else {
            return -1;
        }
    }
};

#endif //SPLAYTREE_H

Примечание

Расширяющееся дерево предоставляет самоизменяющуюся структуру — структуру, характеризующуюся тенденцией хранить узлы, к которым часто происходит обращение, вблизи верхушки дерева, в то время как узлы, к которым обращение происходит редко, перемещаются ближе к листьям. Таким образом время обращения к часто посещаемым узлам будет меньше, а время обращения к редко посещаемым узлам — больше среднего.

Расширяющееся дерево не обладает никакими явными функциями балансировки, но процесс скоса узлов к корню способствует поддержанию дерева в сбалансированном виде.

См. также

  • Сбалансированные (самобалансирующиеся) деревья:

Литература

  • Томас Х. Кормен и др. Алгоритмы: построение и анализ. — 2-е изд. — М.: Издательский дом «Вильямс», 2007. — С. 1296. — ISBN 5-8459-0857-4.
  • Daniel Sleator, Robert Tarjan. A data structure for dynamic trees. — Journal of Computer and System Sciences, 1983. — С. 262—391.

Read other articles:

Pour les articles homonymes, voir Ding Dong. Cet article est une ébauche concernant une chanson, le Concours Eurovision de la chanson et les Pays-Bas. Vous pouvez partager vos connaissances en l’améliorant (comment ?) selon les recommandations des projets correspondants. Ding-a-dong Chanson de Teach-In auConcours Eurovision de la chanson 1975 Sortie 1975 Langue Anglais Auteur Will Luikinga (nl), Eddy Ouwens (nl) Compositeur Dick Bakker (nl) Classement 1re (152 po...

 

Datuk ri BandangLahirAbdul MakmurAbad 16Koto Tangah, Minangkabau MeninggalAbad 17Tallo, Kerajaan Tallo, SulawesiNama lainKhatib TunggalPekerjaanUlamaDikenal atasPenyebar Islam di Luwu, Gowa, Tallo, Kerajaan Gantarang (Sulawesi), Kutai (Kalimantan) dan Kerajaan Bima (Nusa Tenggara) Datuk Ri Bandang yang bernama asli Abdul Makmur dengan gelar Khatib Tunggal adalah seorang ulama dari Koto Tangah, Minangkabau yang menyebarkan agama Islam ke kerajaan-kerajaan di wilayah timur nusantara, yait...

 

Lambda, lambang gerakan Identitarian/Identitarianisme yang biasa dipakai di Eropa oleh Generation Identity dan terkadang negara lainnya, yang ditujukan untuk mengenang Pertempuran Thermopylae[1] Gerakan Identitarian atau Identitarianisme adalah sebuah ideologi politik sauap kanan jauh Eropa pasca-Perang Dunia II[2] yang mendorong hak orang keturunan Eropa untuk mengklaim bahwa budaya dan wilayahnya dikhususkan bagi orang-orang yang dikatakan sebagai orang Eropa. Bermula dari P...

Monterosso al MareComune di Monterosso al MareKoordinat: 44°08′45″N 09°39′15″E / 44.14583°N 9.65417°E / 44.14583; 9.65417Luas • Total11,25 km2 (434 sq mi)Ketinggian12 m (39 ft)Populasi (30 September 2009) • Total1.522DemonimMonterossiniKode area telepon0187Situs webSitus web resmi Monterosso al Mare adalah sebuah kota dan comune yang terletak di Provinsi La Spezia, Liguria, Italia utara. Monterosso al Ma...

 

Halaman ini berisi artikel tentang seorang sastrawan Asamiya dari Lembah Assam, India. Untuk daftar tokoh dari Assam, lihat Daftar tokoh dari Assam. Indira GoswamiLahir(1942-11-14)14 November 1942Guwahati, IndiaMeninggal29 November 2011(2011-11-29) (umur 69)[1]GMCH, Guwahati, Assam, India[2]Nama penaMamoni Raisom GoswamiPekerjaanAktivis, penyunting, penyair, profesor dan penulisKebangsaanIndiaPeriode1956–2011GenreSastra AssamKarya terkenal-The Moth Eaten Howda...

 

Town in Massachusetts, United StatesAshby, MassachusettsTownAerial photo of Ashby, looking toward the center of town (this was taken prior to the construction of the public safety building). SealLocation in Middlesex County in MassachusettsCoordinates: 42°40′40″N 71°49′15″W / 42.67778°N 71.82083°W / 42.67778; -71.82083CountryUnited StatesStateMassachusettsCountyMiddlesexSettled1676Incorporated1767Government • TypeOpen town meeting • ...

For other people named George Burling, see George Burling (disambiguation). George Childs BurlingBorn(1834-02-17)February 17, 1834Burlington County, New JerseyDiedDecember 24, 1885(1885-12-24) (aged 51)Philadelphia, PennsylvaniaPlace of burialHarleigh Cemetery, Camden, New JerseyAllegianceUnited States of AmericaUnionService/branchUnion ArmyRank Colonel Brevet Brigadier GeneralBattles/warsAmerican Civil War George Childs Burling (February 17, 1834 – December 24, 1885) was a United ...

 

List of notable people from Arkansas, United States This article has multiple issues. Please help improve it or discuss these issues on the talk page. (Learn how and when to remove these template messages) This biography of a living person needs additional citations for verification. Please help by adding reliable sources. Contentious material about living persons that is unsourced or poorly sourced must be removed immediately from the article and its talk page, especially if potentially libe...

 

Church in Georgia, United StatesFirst Universalist ChurchFirst Universalist ChurchLocation16 East Harris Street, Atlanta, GeorgiaCountryUnited StatesDenominationUniversalistHistoryFounded1895Founder(s)Rev. Q.H. Shinn, Rev. W.H. McGlauflin, Young People's Christian UnionDedicatedJul 15, 1900ArchitectureStyleEnglish GothicConstruction cost$12,000Demolished1920SpecificationsMaterialsStained Glass Windows: The Sower, The Nativity, The Resurrection. The First Universalist Church of Atlanta, organi...

Distributore di benzina a Hiroshima, Giappone. Con l'espressione lobby dell'energia si indica generalmente un gruppo di aziende del settore energetico (carbone, elettricità, gas, petrolio) che attraverso una serie di azioni tentano di influenzare la politica energetica di singoli Stati o su scala internazionale. Alcune tra le più grandi aziende e corporazioni del settore energetico come ExxonMobil, Royal Dutch Shell, BP, Total S.A., Chevron Corporation, ConocoPhillips, General Electric, Sou...

 

Bolt-action rifle Vz. 98/22 TypeBolt-action riflePlace of originCzechoslovakiaService historyIn service1922 – PresentUsed bySee UsersWarsWarlord EraChinese Civil WarProduction historyDesigned1922ManufacturerZbrojovka BrnoProduced1924-1930SpecificationsMass4.3 kg (9.5 lb) loadedLength124.4 cm (49.0 in)Cartridge7.92×57mm Mauser7×57mm Mauser7.65×53mm MauserCaliber8 mm (0.31 in)ActionBolt-actionRate of fire10–15 rpmMuzzle vel...

 

Artikel ini perlu diwikifikasi agar memenuhi standar kualitas Wikipedia. Anda dapat memberikan bantuan berupa penambahan pranala dalam, atau dengan merapikan tata letak dari artikel ini. Untuk keterangan lebih lanjut, klik [tampil] di bagian kanan. Mengganti markah HTML dengan markah wiki bila dimungkinkan. Tambahkan pranala wiki. Bila dirasa perlu, buatlah pautan ke artikel wiki lainnya dengan cara menambahkan [[ dan ]] pada kata yang bersangkutan (lihat WP:LINK untuk keterangan lebih lanjut...

Cet article est une ébauche concernant une chanson, le Concours Eurovision de la chanson et la Suède. Vous pouvez partager vos connaissances en l’améliorant (comment ?) selon les recommandations des projets correspondants. Som en dröm Chanson de Östen Warnerbring auConcours Eurovision de la chanson 1967 Sortie 1967 Langue Suédois Genre Pop Auteur Patrice Hellberg Compositeur Marcus Österdahl (en), Curt Peterson Classement 8e (ex-æquo) (7 points) Chansons représentan...

 

Part of the Greco-Italian War This article needs additional citations for verification. Please help improve this article by adding citations to reliable sources. Unsourced material may be challenged and removed.Find sources: Battle of Morava–Ivan – news · newspapers · books · scholar · JSTOR (June 2015) (Learn how and when to remove this message) Battle of Morava–IvanPart of the Greco-Italian WarKathimerini announcing the triumph of the Greek arms....

 

Тамга племени чепни согласно М. Кашгари Чепни (также: джебни; туркм. Çepni) - историческое туркменское племя из списка 24-х огузо-туркменских племен, ведущих происхождение от внуков древнего родоначальника туркмен Огуз-хана. Содержание 1 Происхождение 2 История 3 Этнонимия 4 П�...

Village in Estonia This article is about the Estonian village. For the soup, see Abula (soup). For the Latin name of the town in Iberia, see Ávila, Spain. For the former municipality and former bishopric in Spain, see Abla. Village in Saare County, EstoniaAbulaVillageCountry EstoniaCountySaare CountyParishSaaremaa ParishTime zoneUTC+2 (EET) • Summer (DST)UTC+3 (EEST) Abula is a village in Saaremaa Parish, Saare County in western Estonia.[1][2] Before the admi...

 

Сельское поселение России (МО 2-го уровня)Новотитаровское сельское поселение Флаг[d] Герб 45°14′09″ с. ш. 38°58′16″ в. д.HGЯO Страна  Россия Субъект РФ Краснодарский край Район Динской Включает 4 населённых пункта Адм. центр Новотитаровская Глава сельского пос�...

 

Catholic school in Zouk Mosbeh, Lebanon Notre Dame University-Louaize جامعة سيدة اللويزةMottoGaudium De VeritateTypeCatholic UniversityEstablished1987 (1978 as LCHE)PresidentFather Bechara KhouryAcademic staff205 full-time298 part-timeStudentsStudent 4,993 (Fall 2019)LocationZouk Mosbeh, LebanonCampusSuburban, 60.29 acres (244,000 m2)Websitewww.ndu.edu.lb Notre Dame University–Louaize (NDU; Arabic: جامعة سيدة اللويزة) is a private Catholic university in ...

DreamsPoster rilis teatrikalSutradaraAkira KurosawaProduserHisao KurosawaMike Y. InoueDitulis olehAkira KurosawaPemeranAkira TeraoMartin ScorseseChishū RyūMieko HaradaMitsuko BaishoPenata musikShinichirô IkebeSinematograferTakao SaitoShôji UedaPenyuntingTome MinamiPerusahaanproduksiAkira Kurosawa USADistributorWarner Bros. (Amerika Serikat)Toho (Jepang)Tanggal rilis 11 Mei 1990 (1990-05-11) Durasi119 menitNegaraJepangAmerika SerikatBahasaJepangFrenchEnglishAnggaran$12 juta Drea...

 

NGC 4296   الكوكبة العذراء[1]  رمز الفهرس NGC 4296 (الفهرس العام الجديد)2MASX J12212838+0639128 (Two Micron All-Sky Survey, Extended source catalogue)KPG 331a (Catalogue of isolated pairs of galaxies in the northern hemisphere)MCG+01-32-017 (فهرس المجرات الموروفولوجي)PGC 39943 (فهرس المجرات الرئيسية)UGC 7409 (فهرس أوبسالا العام)VCC 475 (Virgo Cluster Catalog)SDSS J122128.38+063...