/* c201.c ********************************************************************** ** Téma: Jednosměrný lineární seznam ** ** Návrh a referenční implementace: Petr Přikryl, říjen 1994 ** Úpravy: Andrea Němcová listopad 1996 ** Petr Přikryl, listopad 1997 ** Přepracované zadání: Petr Přikryl, březen 1998 ** Přepis do jazyka C: Martin Tuček, říjen 2004 ** Úpravy: Kamil Jeřábek, září 2020 ** Daniel Dolejška, září 2021 ** Daniel Dolejška, září 2022 ** ** Implementujte abstraktní datový typ jednosměrný lineární seznam. ** Užitečným obsahem prvku seznamu je celé číslo typu int. ** Seznam bude jako datová abstrakce reprezentován proměnnou typu List. ** Definici konstant a typů naleznete v hlavičkovém souboru c201.h. ** ** Vaším úkolem je implementovat následující operace, které spolu s výše ** uvedenou datovou částí abstrakce tvoří abstraktní datový typ List: ** ** List_Dispose ....... zrušení všech prvků seznamu, ** List_Init .......... inicializace seznamu před prvním použitím, ** List_InsertFirst ... vložení prvku na začátek seznamu, ** List_First ......... nastavení aktivity na první prvek, ** List_GetFirst ...... vrací hodnotu prvního prvku, ** List_DeleteFirst ... zruší první prvek seznamu, ** List_DeleteAfter ... ruší prvek za aktivním prvkem, ** List_InsertAfter ... vloží nový prvek za aktivní prvek seznamu, ** List_GetValue ...... vrací hodnotu aktivního prvku, ** List_SetValue ...... přepíše obsah aktivního prvku novou hodnotou, ** List_Next .......... posune aktivitu na další prvek seznamu, ** List_IsActive ...... zjišťuje aktivitu seznamu. ** ** Nemusíte ošetřovat situaci, kdy místo legálního ukazatele na seznam předá ** někdo jako parametr hodnotu NULL. ** ** Svou implementaci vhodně komentujte! **/ #include "c201.h" #include // printf #include // malloc, free bool error_flag; bool solved; /** * Vytiskne upozornění na to, že došlo k chybě. Nastaví error_flag na logickou 1. * Tato funkce bude volána z některých dále implementovaných operací. */ void List_Error(void) { printf("*ERROR* The program has performed an illegal operation.\n"); error_flag = true; } /** * Provede inicializaci seznamu list před jeho prvním použitím (tzn. žádná * z následujících funkcí nebude volána nad neinicializovaným seznamem). * Tato inicializace se nikdy nebude provádět nad již inicializovaným * seznamem, a proto tuto možnost neošetřujte. Vždy předpokládejte, * že neinicializované proměnné mají nedefinovanou hodnotu. * * @param list Ukazatel na strukturu jednosměrně vázaného seznamu */ void List_Init( List *list ) { list->firstElement = NULL; list->activeElement = NULL; list->currentLength = 0; } /** * Zruší všechny prvky seznamu list a uvede seznam list do stavu, v jakém se nacházel * po inicializaci. Veškerá paměť používaná prvky seznamu list bude korektně * uvolněna voláním operace free. * * @param list Ukazatel na inicializovanou strukturu jednosměrně vázaného seznamu **/ void List_Dispose( List *list ) { while (list->firstElement != NULL) { ListElementPtr tmp = list->firstElement; list->firstElement = list->firstElement->nextElement; free(tmp); } list->activeElement = NULL; list->currentLength = 0; } /** * Vloží prvek s hodnotou data na začátek seznamu list. * V případě, že není dostatek paměti pro nový prvek při operaci malloc, * volá funkci List_Error(). * * @param list Ukazatel na inicializovanou strukturu jednosměrně vázaného seznamu * @param data Hodnota k vložení na začátek seznamu */ void List_InsertFirst( List *list, int data ) { ListElementPtr newElement = (ListElementPtr) malloc(sizeof(struct ListElement)); if (newElement == NULL) { List_Error(); return; } newElement->data = data; newElement->nextElement = list->firstElement; list->firstElement = newElement; list->currentLength++; } /** * Nastaví aktivitu seznamu list na jeho první prvek. * Funkci implementujte jako jediný příkaz, aniž byste testovali, * zda je seznam list prázdný. * @param list Ukazatel na inicializovanou strukturu jednosměrně vázaného seznamu */ void List_First( List *list ) { list->activeElement = list->firstElement; } /** * Prostřednictvím parametru dataPtr vrátí hodnotu prvního prvku seznamu list. * Pokud je seznam list prázdný, volá funkci List_Error(). * * @param list Ukazatel na inicializovanou strukturu jednosměrně vázaného seznamu * @param dataPtr Ukazatel na cílovou proměnnou */ void List_GetFirst( List *list, int *dataPtr ) { if (list->firstElement == NULL) { List_Error(); return; } *dataPtr = list->firstElement->data; } /** * Zruší první prvek seznamu list a uvolní jím používanou paměť. * Pokud byl rušený prvek aktivní, aktivita seznamu se ztrácí. * Pokud byl seznam list prázdný, nic se neděje. * * @param list Ukazatel na inicializovanou strukturu jednosměrně vázaného seznamu */ void List_DeleteFirst( List *list ) { if (list->firstElement != NULL) { ListElementPtr tmp = list->firstElement; list->firstElement = list->firstElement->nextElement; if (list->activeElement == tmp) { list->activeElement = NULL; } free(tmp); list->currentLength--; } } /** * Zruší prvek seznamu list za aktivním prvkem a uvolní jím používanou paměť. * Pokud není seznam list aktivní nebo pokud je aktivní poslední prvek seznamu list, * nic se neděje. * * @param list Ukazatel na inicializovanou strukturu jednosměrně vázaného seznamu */ void List_DeleteAfter( List *list ) { if (list->activeElement != NULL && list->activeElement->nextElement != NULL) { ListElementPtr tmp = list->activeElement->nextElement; list->activeElement->nextElement = tmp->nextElement; free(tmp); list->currentLength--; } } /** * Vloží prvek s hodnotou data za aktivní prvek seznamu list. * Pokud nebyl seznam list aktivní, nic se neděje! * V případě, že není dostatek paměti pro nový prvek při operaci malloc, * zavolá funkci List_Error(). * * @param list Ukazatel na inicializovanou strukturu jednosměrně vázaného seznamu * @param data Hodnota k vložení do seznamu za právě aktivní prvek */ void List_InsertAfter( List *list, int data ) { if (list->activeElement != NULL) { ListElementPtr newElement = (ListElementPtr) malloc(sizeof(struct ListElement)); if (newElement == NULL) { List_Error(); return; } newElement->data = data; newElement->nextElement = list->activeElement->nextElement; list->activeElement->nextElement = newElement; list->currentLength++; } } /** * Prostřednictvím parametru dataPtr vrátí hodnotu aktivního prvku seznamu list. * Pokud seznam není aktivní, zavolá funkci List_Error(). * * @param list Ukazatel na inicializovanou strukturu jednosměrně vázaného seznamu * @param dataPtr Ukazatel na cílovou proměnnou */ void List_GetValue( List *list, int *dataPtr ) { if (list->activeElement == NULL) { List_Error(); return; } *dataPtr = list->activeElement->data; } /** * Přepíše data aktivního prvku seznamu list hodnotou data. * Pokud seznam list není aktivní, nedělá nic! * * @param list Ukazatel na inicializovanou strukturu jednosměrně vázaného seznamu * @param data Nová hodnota právě aktivního prvku */ void List_SetValue( List *list, int data ) { if (list->activeElement != NULL) { list->activeElement->data = data; } } /** * Posune aktivitu na následující prvek seznamu list. * Všimněte si, že touto operací se může aktivní seznam stát neaktivním. * Pokud není předaný seznam list aktivní, nedělá funkce nic. * * @param list Ukazatel na inicializovanou strukturu jednosměrně vázaného seznamu */ void List_Next( List *list ) { if (list->activeElement != NULL) { list->activeElement = list->activeElement->nextElement; } } /** * Je-li seznam list aktivní, vrací nenulovou hodnotu, jinak vrací 0. * Tuto funkci je vhodné implementovat jedním příkazem return. * * @param list Ukazatel na inicializovanou strukturu jednosměrně vázaného seznamu */ int List_IsActive( List *list ) { return list->activeElement != NULL; } /* Konec c201.c */