7. Obojsmerný lineárny zoznam
7.2 Problém - Faktoriál
Vytvorte program na výpočet hodnoty n! (n - faktoriálu) s využitím vhodnej dynamickej údajovej štruktúry.
Riešenie
Program na výpočet faktoriálu pre dané prirodzené číslo n nechýba v úvode žiadneho kurzu programovania.
Ak vám niekto "prikáže naprogramovať faktoriál", spomeniete si na matematickú definíciu:
a po chvíli je na svete program:
int n, i;
unsigned int fakt = 1;
scanf("%d", &n);
for (i = 1; i <= n; i++) fakt *= i;
printf("%d ! = %d", n, fakt);
Algoritmus je síce v poriadku, avšak program bude fungovať len ak n<13. Prečo? Ak údajový typ unsigned int
zaberá v pamäti 4 bajty, tak výsledná hodnota
13! = 6227020800 je už väčšia ako maximálna prípustná hodnota
tohto typu. My však chceme určiť hodnotu n! pre veľké n - koľko je
100!, 789!, 1500! ... ? Zaujímať nás bude navyše nielen samotná hodnota
výsledku, ale i počet cifier.
Pri riešení využijeme dynamickú údajovú štruktúru
obojsmerný lineárny zoznam. Cifry faktoriálu budú uložené v jeho
prvkoch - v programe ich vypočítame "manuálne" postupným násobením
cifru po cifre s pamätaním prenosu. Algoritmus okrem iného spôsobu
uchovávania hodnoty faktoriálu v podstate kopíruje "tradičné" riešenie
s využitím cyklu so známym počtom opakovaní. Postupujeme takto:
Najskôr si pripravíme údajovú štruktúru, v ktorej budeme
priebežne uchovávať medzivýsledok. Pôjde o obojsmerný zoznam prvkov
typu TPrvok : typedef struct prvok {
char cifra;
struct prvok *predch;
struct prvok *nasled;
} TPrvok;
Vytvorenie prvého prvku s hodnotou 1 môžeme pokladať za úvodnú inicializáciu:
Prvý prvok zatiaľ nemá predchodcu ani nasledovníka, prvá cifra je zároveň poslednou (keďže je jediná :-)
Potom už zrealizujeme vlastný výpočet. Postupne v cykle for vypočítame hodnotu 1!, 2!, 3!, ..., (n-1)! a v poslednom opakovaní napokon n!
Nech n = 8. Na obrázku je znázornený zoznam po výpočte hodnoty 7! = 5040:
Počítajme teraz hodnotu 8! = 8.7!
Násobíme od poslednej cifry, pomocný ukazovateľ preto nastavíme na posledný prvok v zozname:
cislica = posl;
násobíme:
cislica = cislica->predch;
cislica = cislica->predch;
cislica = cislica->predch;
Prešli sme postupne celým zoznamom. Posledný prenos je ale rôzny od nuly. Preto pridáme na začiatok zoznamu nový prvok (ďalšiu cifru):
cislica = (TPrvok*)malloc(sizeof(TPrvok));
Pridať
nový prvok znamená nielen alokovať pamäť, ale aj naplniť jeho hodnotovú
časť príslušnou cifrou a nastaviť správne ukazovatele. Prvok
pridávame na začiatok - predchodcu teda nemá. Aktualizujeme aj hodnotu
ukazovateľa na prvú cifru (máme nový začiatok zoznamu).
Voľba údajovej štruktúry sa ukázala výhodná -
v jednom smere prechádzame zoznamom pri násobení po cifrách,
v opačnom smere pri výpise výsledku.
Pre väčšie n
nemusí byť posledný prenos jednociferné číslo! Na začiatok pôvodného
zoznamu sa potom pridáva viac cifier (nových prvkov). Počet cifier
výsledku môžeme zistiť pri výpise výsledku na obrazovku.
[Program]
|