Na této stránce se používá SVG a MathML.
Firefox je umí a některé další prohlížeče se pro ně dají upravit.
    Zadání  9. cvičení  —  v den  24. dubna 2023

       Zásobník — Stack

        abstraktní datový typ

(Alternativní informace k zásobníku.)

Zásobník obecně může být ledacos k uschovávání. V našem případě budeme mluvit o entitě, pro kterou platí,
že jakožto první se výjme to, co bylo vloženo poslední (a že jakožto poslední se výjme to, co bylo vloženo první.
Anglickými zkratkami: LIFO, respective FILO.)
Takováto záležitost může mít povahu mechanickou, například u zásobníků automatických zbraní (u nichž nezáleží
na pořadí, ale je důležitá jednoduchost.)
V programování, ale i obecně při mnoha příležitostech je právě ona „obrácenost” důležitá: vracíme se k poslednímu rozpracovanému …
Abstraktně: Nechť Z je zásobník, pak (jak už víme) Aby náš arsenál byl úplný, tak ještě musíme mít možnost ho inicialisovat a ptát se na to, zda je zásobník prázdný, případně plný. Mnohdy se ještě přidává operace zpřístupňující hodnotu na vrcholu zásobníku,
abychom ji nemuseli vyjímat a hned zase vkládat - což je obojí „náročnější”.
  Logická spojka ∧ (konjunkce) tady není komutativní ona a i ⇒ (implikace):
předepisuje pořadí vyhodnocovaných funkcí a prováděných operací
 
Axiomy  jePlný(Z)      ~vlož(Z, něco)
  ~jePlný(Z) ∧ vlož(ZA)      vyjmi(Z, něco) ∧ něco = A
  ~jePlný(Z) ∧ vlož(ZA)  ∧ ~jePlný(Z) ∧ vlož(ZB)      vyjmi(Z, něco) ∧ něco = B  ∧ vyjmi(Z, něco) ∧ něco = A
 ~jePlný(Z) ∧ vlož(ZA)      vrchol(Z, něco) ∧ něco = A
  ~jePlný(Z) ∧ vlož(ZA)  ∧ ~jePlný(Z) ∧ vlož(ZB)      vrchol(Z, něco) ∧ něco = B  ∧ vrchol(Z, něco) ∧ něco = B
  inicialisuj(Z)      jePrazdný(Z)
 ~jePlný(Z)  ∧ vlož(ZA)      ~jePrazdný(Z)
 jePrazdný(Z)      ~vyjmi(Z, něco)

Takovýto zásobník lze realisovat mechanicky, elektr(on)icky či to úplně
anebo alespoň částečně „zašít” do procesoru či to implementovat softwareově - naprogramovat to.
To je vaše zadání.
V předepsaných funkcích nic nevypisujte a netestujte, před vyjmutím (ze zásobníku) se volající program
musí sám přesvědčit příslušnou funkcí, zda zásobník není prázdný (a adekvátně k volajícímu programu
na to reagovat) a analogicky při vkládání do plného.
Vaše různě implementované funkce by měly reagovat stejně.
Vaše zadání jsou implementace polem a spojovým seznamem:

Implementace polem:

Vkládá se a vyjímá ve všech případech jen po hodnotách.
 
V zásobníku budeme mít pole (hodnot jeho položek) zadané velikosti, index vrcholu a (konstantu) velikost onoho pole.
Index vrcholu je podle vaší volby buď index položky pole za poslední vloženou (za první na výjmutí) hodnotou
anebo index položky pole poslední vložené (první, která je na řadě na výjmutí) hodnoty.
 
 
Index Po inicialisaci je zásobník prázdný a není plný Zásobník prázdný nelze vyjímat Zásobník není prázdný lze vyjímat Zásobník není plný lze vkládat d c y x b a vlož d c y x b a vyjmi vyjmuto x y a b c d Start
Nadefinujte si structureu (nejlépe jako typ), kde bude pole, jeho velikost a index vrcholu zásobníku.
Ostatní si najděte na přednáškách a na internetu.



Implementace spojovým seznamem:

z posledně vložená hodnota předposledně vložená hodnota -25 prvně vložená hodnota

 je opět NULL.


#define TEXT_LENGTH 8
    
typedef char valueType[TEXT_LENGTH];

//typedef unsigned int valueType;

typedef struct mmbr {
            valueType value;
            struct mmbr *next;
        } member;

typedef member* stack; 
Při implementaci zásobníku spojovým seznamem, je důležité vědět, že přestože formálné vypadají stejně,
má zásobník méně operací (odebírá či přidává se hlava).
Dále po vyjmutí vracíte operačnímu systému paměť (free)
a náležitě k tomu při vkládání musíte paměť naalokovat.
Operace zásobníku pracují buď jen se zásobníkem anebo se zásobníkem a hodnotou.
U této implementace (spojovým seznamem), test jePlny bude vždy vracet 0 (false),
protože předpokládáme, že pokud se program nezacyklí,
pak operační systém bude vždy mít dost paměti na to, aby ji mohl přidělit.

Hlavičkový soubor funkcí pro práci se zásobníkem stack.h:
/**
 * Header file for stack operations
 * 
 * @file stack.h
 * @author   A.  Zlamal
 * @version 2020 04 15  
 * 
 */

/**
 *  Inicialize the given stack.
 *  
 *  Inicializuje zadany zasobnik.
 *
 *  @param[in, out]  s  the address of the stack to inicialize.
 *                      adresa zasobniku, jenz se ma inicialisovat.
 *                      
 *  @param[in]  sz  the size of the stack to inicialize. 
 *                  IN CASE OF IMPLEMENTATION BY LINKED LIST SIZE IS OMITTED.
 *                  velikost zasobniku, jenz se ma inicialisovat.
 *                  V PRIPADE IMPLEMENTACE SPOJOVYM SEZNAMEM SE VELIKOST OPOMIJI.
 */
void inicialisuj(stack *s, unsigned int sz);

/**
 *  Push the value of the second parametr to the stack pointed by the first parametr.
 *  Vlozi hodnotu druheho parametru do zasobniku zadaneho prvním parametrem.   
 *
 *  @param[in, out]  s  the address of the stack, into which is to be pushed.
 *                      adresa zasobniku, do nejz se ma vlozit.
 *   
 *  @param[in]  pv  the address, from which is to load the pushed value.
 *                  adresa, z niz se ma do zasobniku vlozit hodnota na ni ulozena.
 *  IMPORTANT WARNING: REACTION ON THE PUSH TO FULL stack IS NOT DEFINED
 *                     AND WITH HIGH PROBABILITY CAUSES FATAL ERROR.
 *                     BEFORE PUSH TEST THE STACK BY FUNCTION jePlny.
 *   (Remark: there is the posibility to join jePlny and vloz
 *               int vlozJisteny(stack *s, valueType *pv)
 *               {
 *                   if (jePlny(s) {
 *                       return 1;
 *                   }
 *                   vloz(s, pv);
 *                   return 0;
 *               }, but I decided for the introduced variant.)
 *  DURAZNE UPOZORNENI: REAKCE NA VLOZENI DO PLNEHO ZASOBNIKU NENI DEFINOVANA
 *                      A S VYSOKOU PRAVDEPODOBNOSTI POVEDE K OSUDOVE CHYBE.
 *                      PRED VKLADANIM OTESTUJTE ZASOBNIK FUNKCI jePlny.
 *   (Poznamka: je mozne spojit jePlny a vloz
 *               int vlozJisteny(stack *s, valueType *pv)
 *               {
 *                   if (jePlny(s) {
 *                       return 1;
 *                   }
 *                   vloz(s, pv);
 *                   return 0;
 *               }, but I decided for the introduced variant.)
 */
void vloz(stack *s, valueType *pv);

/**
 *  Pop the value from the stack pointed by the first parametr. 
 *  and store it into address given by the second parametr.
 *  
 *  Vyjme hodnotu ze zasobniku zadaneho prvním parametrem 
 *  a ulozi ji na adresu danou druhym parametrem.   
 *   
 *  @param[in, out]  s  the address of the stack, from which is to be poped.
 *                      adresa zasobniku, z nejz se ma vybrat.
 *  
 *  @param[out]  pv  the address, into which is to store the poped value.
 *                   adresa, na niz se ma vybrana hodnota ulozit.
 *
 *  IMPORTANT WARNING: REACTION ON THE POP FROM EMPTY STACK IS NOT DEFINED
 *                        AND WITH HIGH PROBABILITY CAUSES FATAL ERROR.
 *                        BEFORE POP TEST THE stack BY FUNCTION jePrazdny.
 *   (Remark: there is the posibility to join stackIsEmpty and pop
 *               int vyjmiJisteny(stack *s, valueType *pv)
 *               {
 *                   if (jePrazdny(q) {
 *                       return 1;
 *                   }
 *                   vyjmi(s, pv);
 *                   return 0;
 *               }, but I decided for the introduced variant.)
 *  DURAZNE UPOZORNENI: REAKCE NA VYBER Z PRAZDNEHO ZASOBNIKU NENI DEFINOVANA
 *                      A S VYSOKOU PRAVDEPODOBNOSTI POVEDE K OSUDOVE CHYBE.
 *                      PRED VYBEREM OTESTUJTE ZASOBNIK FUNKCI jePrazdny.
 *   (Poznamka: je mozne spojit stackIsFull a pop
 *               int vyjmiJisteny(stack *s, demanded_t *pv)
 *               {
 *                   if (jePrazdny(q) {
 *                       return 1;
 *                   }
 *                   vyjmi(s, pv);
 *                   return 0;
 *               }, but I decided for the introduced variant.)
 */
void vyjmi(stack *s, valueType *pv);

/**
 *  Returns the value, which is on the top of the stack. 
 *  Vrati hodnotu, jez je na vrcholu zasobniku. 
 *
 *  @param[in, out]  s  the address of the stack, from which is to be copied the value on it's top.
 *                      adresa zasobniku, z jehoz vrcholu se ma zkopirovat hodnota.
 *  
 *  @param[out]  pv  the address, into which is to store the value, which is on it's top.
 *                   adresa, na niz se ma hodnota z jeho vrcholu ulozit.
 *
 *  IMPORTANT WARNING: REACTION ON THE REFERENCING THE TOP OF THE EMPTY stack IS NOT DEFINED
 *                     AND WITH HIGH PROBABILITY CAUSES FATAL ERROR.
 *                     BEFORE USING TOP TEST THE STACK BY FUNCTION jePrazdny.
 *   (Remark: there is the posibility to join jePrazdny and vrchol
 *               int vrcholJisteny(stack *s, valueType *pv)
 *               {
 *                   if (jePrazdny(q) {
 *                       return 1;
 *                   }
 *                   vrchol(s, pv);
 *                   return 0;
 *               }, but I decided for the introduced variant.)
 *  DURAZNE UPOZORNENI: REAKCE NA ODKAZ NA VRCHOL PRAZDNEHO ZASOBNIKU NENI DEFINOVANA
 *                      A S VYSOKOU PRAVDEPODOBNOSTI POVEDE K OSUDOVE CHYBE.
 *                      PRED REFERENCOVANIM VRCHOLU OTESTUJTE ZASOBNIK FUNKCI jePrazdny.
 *   (Poznamka: je mozne spojit jePrazdny a vrchol
 *               int vrcholJisteny(stack *s, valueType *pv)
 *               {
 *                   if (jePrazdny(q) {
 *                       return 1;
 *                   }
 *                   vrchol(s, pv);
 *                   return 0;
 *               }, but I decided for the introduced variant.)
 */
void vrchol(stack *s, valueType *v);

/**
 *  Tests if the stack is empty. 
 *  Testuje zda je zasobnik prazdny. 
 *   
 *  @param[in, out]  s  the address of the stack.
 *                      adresa zasobniku.
 *   
 *  @return  non zero iff the stack is empty; otherwise zero.
 *           nenulovou hodnotu, jen je-li zasobnik prazdny; v opacnem pripade nulu. 
 */
int jePrazdny(stack *s);

/**
 *  Tests if the stack is full. 
 *  Testuje zda je zasobnik plny.  
 *
 *  @param[in, out]  s  the address of the stack.
 *                      adresa zasobniku.
 *   
 *  @return  zero iff the stack isn't full; otherwise non zero.
 *           nulu jen neni-li zasobnik plny; v opacnem pripade nenulovou hodnotu.
 */
int jePlny(stack *s);

/**
 *  Free the memory allocated for the stack in case of implentation by linked list.
 *                  (The same effect as initialize, but without memory leaks tested by valgrind.)
 *  Uvolni pamet alokovanou pro zasobnik v pripade implementace spojovym seznamem.
 *                  (Stejny efekt jako inicialisuj, ale bez memory leaku zjistovanych valgrindem.)
 *   
 *  @param[in, out]  s  the address of the stack.
 *                      adresa zasobniku.
 */
void uvolniPamet(stack *s);


Soubor pro demonstraci práce se zásobníkem main.c:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "definedType.h"
#include "stack.h"

/**
 * File with function main for demonstration stack operations
 *
 * @file main.c 
 * @author   A.  Zlamal
 * @version 2020 04 15  
 * 
 */

int main()
{
    stack z;
    valueType y;
    int isf;

    inicialisuj(&z, 8); 
    printf("Zadavejte na radky znakove retezce. Ta se budou vkladat do zasobniku.\n"
           "Zadavani se ukoncuje prazdnym radkem.\n");
    while ((fgets(y, TEXT_LENGTH, stdin) != NULL) && (*y != '\n') && !(isf = jePlny(&z))) {
        y[strlen(y) - 1] = '\0';
        vloz(&z, &y);
    }
    if (isf) {
        printf("Zasobnik je plny: hodnota %s byla posledni, ktera se jeste vesla.\n", y);
    }
    printf("Konec vkladani do zasobniku.\n");
    printf("Nejvyse dvakrat vyber ze zasobniku:\n");
    if (!jePrazdny(&z)) {
        vrchol(&z, &y);
        printf("    %s :: ", y);
        vyjmi(&z, &y);
        printf("%s\n", y);
    }
    if (!jePrazdny(&z)) {
        vrchol(&z, &y);
        printf("    %s :: ", y);
        vyjmi(&z, &y);
        printf("%s\n", y);
    }
    printf("Nasleduje dalsi vkladani do zasobniku:\n");
    while( (fgets(y, TEXT_LENGTH, stdin) != NULL) && (*y != '\n') && !(isf = jePlny(&z))) {
        y[strlen(y) - 1] = '\0';
        vloz(&z, &y);
    }
    if (isf) {
        printf("Zasobnik je plny: hodnota %s byla posledni, ktera se jeste vesla.\n", y);
    }
    printf("Vyber vsech hodnot ze zasobniku:\n");
    while (!jePrazdny(&z)) {
        vrchol(&z, &y);
        printf("    %s :: ", y);
        vyjmi(&z, &y);
        printf("%s\n", y);
    }
    printf("\nNasleduje dalsi vkladani do zasobniku a opet vyber vseho z nej:\n");
    while( (fgets(y, TEXT_LENGTH, stdin) != NULL) && (*y != '\n') && !(isf = jePlny(&z))) {
        y[strlen(y) - 1] = '\0';
        vloz(&z, &y);
    }
    if (isf) {
        printf("Zasobnik je plny: hodnota %s byla posledni, ktera se jeste vesla.\n", y);
    }
    printf("Vyber vsech hodnot ze zasobniku:\n");
    while (!jePrazdny(&z)) {
        vrchol(&z, &y);
        printf("    %s :: ", y);
        vyjmi(&z, &y);
        printf("%s\n", y);
    }
    uvolniPamet(&z);
    printf("Byla uvolnena pamet zasobniku: %s.\n", z == NULL ? "NULL" : z->value);
    return EXIT_SUCCESS;
}