Indexerat binÀrt trÀd

Indexerat binÀrt trÀd

Jag stötte pÄ en uppgift av följande slag. Det Àr nödvÀndigt att implementera en datalagringsbehÄllare som tillhandahÄller följande funktionalitet:

  • lĂ€gg till ett nytt element
  • ta bort ett element efter dess ordningsnummer
  • hĂ€mta ett element efter dess ordningsnummer
  • data lagras i sorterad ordning

Data lÀggs stÀndigt till och tas bort, strukturen mÄste sÀkerstÀlla snabb hastighet. I början försökte jag implementera nÄgot sÄdant med hjÀlp av standardbehÄllare frÄn std. Den vÀgen var inte framgÄngsrik, och jag kom till insikten att jag behövde implementera nÄgot sjÀlv. Det enda som kom i minnet var att anvÀnda ett binÀrt söktrÀd. Eftersom det uppfyller kraven för snabb inlÀggning, borttagning och lagring av data i sorterad ordning. Nu Äterstod bara att lista ut hur man ska indexera alla element och rÀkna om indexen nÀr trÀdet förÀndras.

struct node_s {    
    data_t data;

    uint64_t weight; // nodens vikt

    node_t *left;
    node_t *right;

    node_t *parent;
};

I artikeln kommer det att vara fler bilder och teori Àn kod. Koden kan ses via lÀnken nedan.

Vikt

För detta utsattes trÀdet för en liten modifiering, ytterligare information om vikt noden. Vikten av en nod Àr antalet efterkommande av denna nod + 1 (vikten av en enda enhet).

Funktionen för att fÄ nodens vikt:

uint64_t bntree::get_child_weight(node_t *node) {
    if (node) {
        return node->weight;
    }

    return 0;
}

För ett blad Àr vikten dÀrför lika med 0.

LĂ„t oss nu gĂ„ vidare till en visuell representation av ett exempel pĂ„ ett sĂ„dant trĂ€d. Med svart fĂ€rg kommer nyckeln pĂ„ noden att visas (vĂ€rdet visas inte, eftersom det inte Ă€r nödvĂ€ndigt), med röd — nodens vikt, med grön — nodens index.

NÀr trÀdet Àr tomt Àr dess vikt 0. LÄt oss lÀgga till rootelementet:

Indexerat binÀrt trÀd

Vikten av trÀdet blir 1, vikten av rootelementet Àr 1. Vikten av rootelementet Àr vikt för trÀdet.

LÄt oss lÀgga till nÄgra fler element:

Indexerat binÀrt trÀd
Indexerat binÀrt trÀd
Indexerat binÀrt trÀd
Indexerat binÀrt trÀd

Varje gÄng ett nytt element lÀggs till, gÄr vi ner genom noderna och ökar viktvÀrdet för varje passerad nod. NÀr en ny nod skapas fÄr den vikten 1. Om en nod med en sÄdan nyckel redan finns, skriver vi om vÀrdet och gÄr tillbaka upp till roten, vilket ÄterstÀller viktvÀrdena för alla de noder vi passerat.
Om en nod tas bort, gÄr vi nerÄt och minskar vikten för de passerade noderna.

Index

LÄt oss nu gÄ vidare till hur man indexerar noder. Noderna lagrar uppenbarligen inte sitt index, utan det berÀknas utifrÄn nodernas vikt. Om de skulle lagra sitt index skulle det krÀva O(n) tid för att uppdatera indexen för alla noder efter varje Àndring av trÀdet.
Vi gÄr vidare till en visuell representation. VÄrt trÀd Àr tomt, vi lÀgger till den första noden:

Indexerat binÀrt trÀd

Den första noden har index 0, och nu finns det tvÄ möjliga fall. I det första fallet kommer rotnodens index att Àndras, i det andra kommer det inte att förÀndras.

Indexerat binÀrt trÀd

Roten har ett vÀnster deltrÀd med vikten 1.

Det andra fallet:

Indexerat binÀrt trÀd

Indexet för roten har inte Àndrats, eftersom vikten av dess vÀnstra deltrÀd förblev 0.

Hur indexet för en nod berÀknas, Àr vikten av dess vÀnstra deltrÀd plus det tal som ges av förÀldern. Vad Àr det hÀr talet? Det Àr indexrÀknaren, som initialt Àr 0, eftersom roten inte har nÄgon förÀlder. Sedan beror allt pÄ om vi gÄr ner till vÀnster barn eller höger. Om vi gÄr till vÀnster, sÄ lÀggs inget till indexrÀknaren. Om vi gÄr till höger, dÄ lÀgger vi till indexet för den aktuella noden.

Indexerat binÀrt trÀd

Till exempel hur indexet för elementet med nyckeln 8 (höger barn av roten) berÀknas. Det Àr "Index för roten" + "vikten av den vÀnstra deltrÀdet av noden med nyckeln 8" + "1" == 3 + 2 + 1 == 6
Indexet för elementet med nyckeln 6 kommer att vara "Index för roten" + 1 == 3 + 1 == 4

Följaktligen, för att fÄ, ta bort ett element efter index krÀvs tid O(log n), eftersom för att fÄ det önskade elementet mÄste vi först hitta det (gÄ ner frÄn roten till detta element).

Djup

UtifrÄn vikten kan man ocksÄ berÀkna djupet pÄ trÀdet. Detta behövs för balansering.
För detta mÄste vikten av den aktuella noden avrundas till det första talet som Àr en potens av 2 som Àr större Àn eller lika med den angivna vikten och ta den binÀra logaritmen av det. PÄ sÄ sÀtt fÄr vi djupet pÄ trÀdet, under förutsÀttning att det Àr balanserat. TrÀdet balanseras efter att en ny nod har lagts till. Jag kommer inte att ge teorin om hur man balanserar trÀd. I kÀllkoderna presenteras en balansfunktion.

Kod för att konvertera vikt till djup.

/*
 * Đ’ĐŸĐ·ĐČращаДт пДрĐČĐŸĐ” Ń‡ĐžŃĐ»ĐŸ ĐČ ŃŃ‚Đ”ĐżĐ”ĐœĐž 2, ĐșĐŸŃ‚ĐŸŃ€ĐŸĐ” Đ±ĐŸĐ»ŃŒŃˆĐ” ОлО Ń€ĐŸĐČĐœĐŸ x
 */
uint64_t bntree::cpl2(uint64_t x) {
    x = x - 1;
    x = x | (x >> 1);
    x = x | (x >> 2);
    x = x | (x >> 4);
    x = x | (x >> 8);
    x = x | (x >> 16);
    x = x | (x >> 32);

    return x + 1;
}

/*
 * ДĐČĐŸĐžŃ‡ĐœŃ‹Đč Đ»ĐŸĐłĐ°Ń€ĐžŃ„ĐŒ ĐŸŃ‚ чОсла
 */
long bntree::ilog2(long d) {
    int result;
    std::frexp(d, &result);
    return result - 1;
}

/*
 * ВДс Đș ĐłĐ»ŃƒĐ±ĐžĐœĐ”
 */
uint64_t bntree::weight_to_depth(node_t *p) {
    if (p == NULL) {
        return 0;
    }

    if (p->weight == 1) {
        return 1;
    } else if (p->weight == 2) {
        return 2;
    }

    return this->ilog2(this->cpl2(p->weight));
}

Sammanfattning

  • insĂ€ttning av en ny nod sker pĂ„ O(log n)
  • borttagning av ett element enligt ordningsnummer sker pĂ„ O(log n)
  • hĂ€mtning av ett element enligt ordningsnummer sker pĂ„ O(log n)

Hastighet O(log n) vi betalar för att alla data lagras i sorterad ordning.

Jag vet inte var en sÄdan struktur kan vara anvÀndbar. Det Àr bara en uppgift för att förstÄ hur trÀd fungerar. Tack för uppmÀrksamheten.

LĂ€nkar

Projektet innehÄller testdata för att kontrollera hastigheten. TrÀdet fylls med 1000000 element. Det sker sekventiell borttagning, insÀttning och hÀmtning av element 1000000 gÄng. Det vill sÀga 3000000 operationer. Resultatet visade sig vara ganska bra ~ 8 sekunder.

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster