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