9. Stromy

9.4 Binárny strom – príklad

Typickým príkladom binárneho stromu je vlastný rodokmeň. Jednotlivé vcholy tohto stromu predstavujú členov rodiny (informácie o nich – napr. meno, rok narodenia, zamestnanie a pod.)

Namiesto ľavého a pravého syna každého vrcholu by sme mali vlastne hovoriť o matke a otcovi.


Napíšeme postupne funkcie, pomocou ktorých budeme s naším rodokmeňom pracovať. Budeme predpokladať, že žiadny dvaja naši príbuzní nemajú rovnaké meno (pre jednoduchosť). Definujme si najskôr typ vrcholu:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

typedef struct vrchol {
	char meno[20];        /* meno */
	struct vrchol *ls;    /* otec */
	struct vrchol *ps;    /* matka */
} TVrchol;

TVrchol *strom = NULL;


Náš strom je zatiaľ prázdny. Vytvorme teda prvý vrchol – koreň stromu:

strom = (TVrchol*)malloc(sizeof(TVrchol));
strcpy(strom->meno, "ja");
strom->ls = NULL;
strom->ps = NULL;

Alebo si rovno pripravme funkciu na vytvorenie nového vrcholu – bude vracať ukazovateľ na vytvorený vrchol:

TVrchol *novy(char *kto)
{
	TVrchol *pom = (TVrchol*)malloc(sizeof(TVrchol));
	pom->ps = NULL;
	pom->ls = NULL;
	strcpy(pom->meno, kto);
	return (pom);
}
Koreň stromu potom vytvoríme takto:
strom = novy("ja");


Teraz by sme chceli do stromu pridať ďalších členov rodiny. Každý nový prvok pridáme na správne miesto – t. j. ako ľavého alebo pravého syna určeného vrcholu.

void pridaj(TVrchol *koren, char *komu, char *kto, char syn)
{
	if (!strcmp(koren->meno, komu)) {
		if (syn == 'P')
			if (koren->ps != NULL) printf("Dany vrchol uz existuje!");
			else koren->ps = novy(kto);

		if (syn == 'L')
			if (koren->ls != NULL) printf("Dany vrchol uz existuje!");
			else koren->ls = novy(kto);
	}
	else {
		if (koren->ls != NULL) pridaj(koren->ls, komu, kto, syn);
		if (koren->ps != NULL) pridaj(koren->ps, komu, kto, syn);
	}
}

Funkcia strcmp porovnáva dva reťazce. Ak sú rovnaké, vráti hodnotu 0!

Pridajme teda do stromu ďalší vrchol:
 
pridaj(strom, "ja", "mama", 'L');
 
Čo sa udeje? V strome hľadáme vrchol s hodnotou „ja“ ktorému máme ako ľavého syna pridať nový vrchol s hodnotou „mama.“ Všimnite si, že strom prehľadávame metódou KLP. Ak hľadaný vrchol nájdeme a zistíme, že už ľavého syna má, vypíšeme o tom oznam na obrazovku.
 
Pridajme do stromu ďalších:
 
pridaj(strom, "ja", "otec", 'P');
pridaj(strom, "otec", "dedko2", 'P');
pridaj(strom, "otec", "babka2", 'L');
 
atď.


Vytvorený rodokmeň („rodostrom“), samozrejme, chceme zviditeľniť:

void vypis(TVrchol *koren) LKP
{
	if (koren != NULL) {
		vypis(koren->ls);
		printf("%s  ", koren->meno);
		vypis(koren->ps);
	}
}

Precvičme si

Napíšte funkciu, ktorá nám umožní zrušiť naraz celý strom (uvoľniť pamäť alokovanú pre jednotlivé vrcholy stromu).

[Riešenie]

Napíšte funkciu, ktorá nám umožní zistiť, či sa v našom rodokmeni nachádza človek s daným menom (nájde daný vrchol). Po skončení tejto funkcie chceme mať navyše k dispozícii aj ukazovateľ na príslušný vrchol.

[Riešenie]

Pri konštrukcii stromu je ideálne, ak má minimálnu výšku (vyhľadávnie je efektívnejšie). Na to je potrebné, aby sme na každej úrovni, s výnimkou poslednej, umiestnili maximálny počet vrcholov. Skonštruujeme takto tzv. dokonale vyvážený strom, v ktorom pre každý vrchol platí, že počet vrcholov v jeho ľavom a pravom podstrome sa líši najviac o jednotku.
 
Napíšte funkciu, ktorá z n vstupných hodnôt vytvorí binárny strom, ktorý bude dokonale vyvážený. Jednotlivé vrcholy umiestnite rovnomerne do ľavého a pravého podstromu! Pracujte so stromom celých čísel.

[Riešenie]