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]
|