Projects/2BIT/winter-semester/IAL 1.DU/c203.c
2026-04-14 19:28:46 +02:00

222 lines
7.9 KiB
C

/* ******************************* c203.c *********************************** */
/* Předmět: Algoritmy (IAL) - FIT VUT v Brně */
/* Úkol: c203 - Fronta znaků v poli */
/* Referenční implementace: Petr Přikryl, 1994 */
/* Přepis do jazyka C: Václav Topinka, září 2005 */
/* Úpravy: Kamil Jeřábek, září 2020 */
/* Daniel Dolejška, září 2021 */
/* Daniel Dolejška, září 2022 */
/* ************************************************************************** */
/*
** Implementujte frontu znaků v poli. Přesnou definici typů naleznete
** v hlavičkovém souboru c203.h (ADT fronta je reprezentována strukturou Queue,
** která obsahuje pole 'array' pro uložení hodnot ve frontě a indexy firstIndex
** a freeIndex. Všechny implementované funkce musí předpokládat velikost pole
** QUEUE_SIZE, i když ve skutečnosti jsou rozměry statického pole definovány
** MAX_QUEUE. Hodnota QUEUE_SIZE slouží k simulaci fronty v různě velkém poli
** a nastavuje se v testovacím skriptu c203-test.c před testováním
** implementovaných funkcí. Hodnota QUEUE_SIZE může nabývat hodnot v rozsahu
** 1 až MAX_QUEUE.
**
** Index firstIndex ukazuje vždy na první prvek ve frontě. Index freeIndex
** ukazuje na první volný prvek ve frontě. Pokud je fronta prázdná, ukazují
** oba indexy na stejné místo. Po inicializaci ukazují na první prvek pole,
** obsahují tedy hodnotu 0. Z uvedených pravidel vyplývá, že v poli je vždy
** minimálně jeden prvek nevyužitý.
**
** Při libovolné operaci se žádný z indexů (firstIndex i freeIndex) nesnižuje
** vyjma případu, kdy index přesáhne hranici QUEUE_SIZE. V tom případě
** se "posunuje" znovu na začátek pole. Za tímto účelem budete deklarovat
** pomocnou funkci NextIndex, která pro kruhový pohyb přes indexy pole
** využívá operaci "modulo".
**
** Implementujte následující funkce:
**
** Queue_Init ...... inicializace fronty
** nextIndex ....... pomocná funkce - viz popis výše
** Queue_IsEmpty ... test na prázdnost fronty
** Queue_IsFull .... test, zda je fronta zaplněna (vyčerpána kapacita)
** Queue_Front ..... přečte hodnoty prvního prvku z fronty
** Queue_Remove .... odstraní první prvek fronty
** Queue_Dequeue ... přečte a odstraní první prvek fronty
** Queue_Enqueue ... zařazení prvku na konec fronty
**
** Nemusíte ošetřovat situaci, kdy místo legálního ukazatele na seznam
** předá někdo jako parametr hodnotu NULL.
**
** Své řešení účelně komentujte!
**
**/
#include "c203.h"
int QUEUE_SIZE = MAX_QUEUE;
bool error_flag;
bool solved;
/**
* Vytiskne upozornění na to, že došlo k chybě.
* Tato funkce bude volána z některých dále implementovaných operací.
*
* TUTO FUNKCI, PROSÍME, NEUPRAVUJTE!
*
* @param error_code Interní identifikátor chyby
*/
void Queue_Error( int error_code ) {
static const char *QERR_STRINGS[MAX_QERR + 1] = {
"Unknown error",
"Queue error: ENQUEUE",
"Queue error: FRONT",
"Queue error: REMOVE",
"Queue error: DEQUEUE",
"Queue error: INIT"
};
if (error_code <= 0 || error_code > MAX_QERR)
{
error_code = 0;
}
printf("%s\n", QERR_STRINGS[error_code]);
error_flag = 1;
}
/**
* Inicializujte frontu následujícím způsobem:
* - všechny hodnoty v poli queue->array nastavte na '*',
* - index na začátek fronty nastavte na 0,
* - index prvního volného místa nastavte také na 0.
*
* V případě, že funkce dostane jako parametr queue == NULL, volejte funkci
* Queue_Error(QERR_INIT).
*
* @param queue Ukazatel na strukturu fronty
*/
void Queue_Init( Queue *queue ) {
if (queue == NULL)
{
Queue_Error(QERR_INIT);
return;
}
for (int i = 0; i < QUEUE_SIZE; i++)
{
queue->array[i] = '*';
}
queue->firstIndex = 0;
queue->freeIndex = 0;
}
/**
* Pomocná funkce, která vrací index následujícího prvku v poli.
* Funkci implementujte jako jediný prikaz využívající operace '%'.
* Funkci nextIndex budete využívat v dalších implementovaných funkcích.
*
* @param index Aktuální index
*/
int nextIndex( int index ) {
return (index + 1) % QUEUE_SIZE;
}
/**
* Vrací nenulovou hodnotu, pokud je frona prázdná, jinak vrací hodnotu 0.
* Funkci je vhodné implementovat jedním příkazem return.
*
* @param queue Ukazatel na inicializovanou strukturu fronty
*/
int Queue_IsEmpty( const Queue *queue ) {
return (queue->firstIndex == queue->freeIndex);
}
/**
* Vrací nenulovou hodnotu, je-li fronta plná, jinak vrací hodnotu 0.
* Funkci je vhodné implementovat jedním příkazem return
* s využitím pomocné funkce nextIndex.
*
* @param queue Ukazatel na inicializovanou strukturu fronty
*/
int Queue_IsFull( const Queue *queue ) {
return (nextIndex(queue->freeIndex) == queue->firstIndex);
}
/**
* Prostřednictvím parametru dataPtr vrátí znak ze začátku fronty queue.
* Pokud je fronta prázdná, ošetřete to voláním funkce Queue_Error(QERR_FRONT).
* Volání této funkce při prázdné frontě je vždy nutné považovat za nekorektní.
* Bývá to totiž důsledek špatného návrhu algoritmu, ve kterém je fronta
* použita. O takové situaci se proto musí programátor-vývojář dozvědět.
* V opačném případě je ladění programů obtížnější!
*
* Při implementaci využijte dříve definované funkce Queue_IsEmpty.
*
* @param queue Ukazatel na inicializovanou strukturu fronty
* @param dataPtr Ukazatel na cílovou proměnnou
*/
void Queue_Front( const Queue *queue, char *dataPtr ) {
if (Queue_IsEmpty(queue))
{
Queue_Error(QERR_FRONT);
return;
}
*dataPtr = queue->array[queue->firstIndex];
}
/**
* Odstraní znak ze začátku fronty queue. Pokud je fronta prázdná, ošetřete
* vzniklou chybu voláním funkce Queue_Error(QERR_REMOVE).
* Hodnotu na uvolněné pozici ve frontě nijak neošetřujte (nepřepisujte).
* Při implementaci využijte dříve definované funkce Queue_IsEmpty a nextIndex.
*
* @param queue Ukazatel na inicializovanou strukturu fronty
*/
void Queue_Remove( Queue *queue ) {
if (Queue_IsEmpty(queue))
{
Queue_Error(QERR_REMOVE);
return;
}
queue->firstIndex = nextIndex(queue->firstIndex);
}
/**
* Odstraní znak ze začátku fronty a vrátí ho prostřednictvím parametru dataPtr.
* Pokud je fronta prázdná, ošetřete to voláním funkce Queue_Error(QERR_DEQUEUE).
*
* Při implementaci využijte dříve definovaných funkcí Queue_IsEmpty,
* Queue_Front a Queue_Remove.
*
* @param queue Ukazatel na inicializovanou strukturu fronty
* @param dataPtr Ukazatel na cílovou proměnnou
*/
void Queue_Dequeue( Queue *queue, char *dataPtr ) {
if (Queue_IsEmpty(queue))
{
Queue_Error(QERR_DEQUEUE);
return;
}
Queue_Front(queue, dataPtr);
Queue_Remove(queue);
}
/**
* Vloží znak data do fronty. Pokud je fronta plná, ošetřete chybu voláním
* funkce Queue_Error(QERR_ENQUEUE). Vkládání do plné fronty se považuje za
* nekorektní operaci. Situace by mohla být řešena i tak, že by operace
* neprováděla nic, ale v případě použití takto definované abstrakce by se
* obtížně odhalovaly chyby v algoritmech, které by abstrakci využívaly.
*
* Při implementaci využijte dříve definovaných funkcí Queue_IsFull a nextIndex.
*
* @param queue Ukazatel na inicializovanou strukturu fronty
* @param data Znak k vložení
*/
void Queue_Enqueue( Queue *queue, char data ) {
if (Queue_IsFull(queue))
{
Queue_Error(QERR_ENQUEUE);
return;
}
queue->array[queue->freeIndex] = data;
queue->freeIndex = nextIndex(queue->freeIndex);
}
/* Konec příkladu c203.c */