Hledání prvku ve stromu

zdrojový text

Funkce search je vlastne cyklus jdouci od korene dolu k listum.
Pokud najde hledany klic, vrati ukazatel na cely uzel stromu.
Pokud nenajde, vraci nullptr.
Parametrem je ukazatel na koren stomu a hodnota hledaneho klice.

Pokud zavolate search (root, 7),
zkopiruje se hodnota ukazatele z promenne root do parametru p
Parametr p mohu menit, aniz bych ovlivnil promennou root.

Konjunkce && :
Pokud je levy parametr false, pravy parametr se jiz nevycisluje a vysledek je false.
V nasem pripade: pokud je p nulovy, vysledek vyrazu p != nullptr && p→key != k je false a cyklus se zastavi.
Pokud p neni nulovy, muzeme otestovat hodnotu p→key a zastavit, pokud potkame hledany klic.

Item * search (Item* p, int k) 
{
        while (p != nullptr && p->key != k) 
        {
            if (k < p->key)
                p = p->left;
            else
                p = p->right;
        }
        return p;
}

Rekurzivní hledání prvku

Rekuzivni varianta hledani prvku, funkce find.
Prvni paramater je ukazatel na koren podstromu, ve kterem hledame.
Pokud je podstrom prazdny vratime nullptr.
Ve zbyvajici casti funkce, je p nenulovy.
Pokud koren podstromu obsahuje hledany klic, vratime ukazatel na tento podstrom.
Pokud je kledany klic mensi nez hodnota v koreni,
pouzijeme rekurzivne funkci find na levy podstrom.
A co tato nova funkce vrati to bude i vysledkem nasi funkce.
return find (p→left, k);

Poznamka: slozene zavorky { } uvnitr funkce nejsou nezbytne.
Za if nebo else nasleduje prave jeden prikaz.

Item * find (Item* p, int k)
{
    if (p == nullptr) 
    {
        return nullptr;
    }
    else if (p->key == k)
    {
        return p;
    }
    else if (k < p->key)
    {
      return find (p->left, k);
    }
    else
    {
       return find (p->right, k);
    }
}

Funkce find je jen slozitejsi variantou funkce search.
Pro hledani ji nejspise nebudeme pouzivat, ale poslouzi nam pri navrhu funkce pro vkladani.

Vkladani prvku do stromu

   void insert (Item * & p, int k)

Prvni parameter je ukazatel a je predavany odkazem ( znak & ).
Pri volani

   insert (root, 7);

se do paratetru p ulozi odkaz na promenou root.
Prekladac odkaz implementuje pomoci “skryteho” ukazatele ( v nasem pripade ukazatele opet na ukazatel. )
Pokud promennou p menime, zmenime i obsah promenne root. Napr. p = new Item;
Pokud promennou p pouzivame, pouziva se obsah promenne root. Napr. p == nullptr;
Pokud cteme polozku p, pristupujeme k polozce root. Napr. p→key == k;

Pokud je strom prazdny, vytvorime novou polozku a jeji adresa je ulozena na misto kde bylo nullptr predstavujici nulovy koren puvodniho stromu.

    if (p == nullptr)
    {
        p = new Item;
        p->key = k;
        p->left = nullptr;
        p->right = nullptr;
    }

Pokud je klic ktery chceme vlozit v koreni prave zpracovaneho stromu. Nebudu delat nic. (Ale muzete ohlasit chybu.)

    else if (p->key == k)
    {
    }

Pokud je klic ktery chceme vlozit mensi nez hodnota v koreni prave zpracovaneho stromu,
rekurzivne zavolam funkci insert.
Jako paramatetr predam koren leveho podstromu.
Odkaz na levy podstrom se ulozi do parametru p nove zavolane funkce insert.

    else if (k < p->key)
    {
        insert (p->left, k);
    }

A podobne pro pravy podstrom. Zde je cela funkce.

void insert (Item * & p, int k)
{
    if (p == nullptr)
    {
        p = new Item;
        p->key = k;
        p->left = nullptr;
        p->right = nullptr;
    }
    else if (p->key == k)
    {
    }
    else if (k < p->key)
    {
        insert (p->left, k);
    }
    else
    {
        insert (p->right, k);
    }
}

Varianty vkládání bez odkazu (reference), ale s ukazatelem na ukazatel.

Můžete porovnat s funkcemi enter a ent, které používají dvojitý ukazatel.
( Jen pro ilustraci, nedoporucuji pouzivat. )

void enter (Item * * p, int k)
{
    if (*p == nullptr)
    {
        *p = new Item;
        (*p)->key = k;
        (*p)->left = nullptr;
        (*p)->right = nullptr;
    }
    else if ((*p)->key == k)
    {
 
    }
    else if (k < (*p)->key)
    {
        enter (&((*p)->left), k);
    }
    else
    {
        enter(&((*p)->right), k);
    }
}
 
void ent (Item * * p, int k)
{
    bool cont = true;
    while (cont)
    {
        if (*p == NULL)
        {
            *p = new Item;
            (*p)->key = k;
            (*p)->left = NULL;
            (*p)->right = NULL;
            cont = false;
        }
        else if ((*p)->key == k) cont = false;
        else if (k > (*p)->key)  p = &((*p)->right);
        else p = &((*p)->left);
    }
}
 
strom_add.txt · Last modified: 2020/03/23 22:07 by 88.103.111.44
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki