pvjc25/du6/list_ops.c

107 lines
3.8 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "list_ops.h"
#include <stdlib.h>
#include <string.h>
// Vytvorí nový zoznam s danou dĺžkou a hodnotami prvkov.
// Prvky sa kopírujú, takže pôvodné pole je nezávislé od výsledného zoznamu.
list_t *new_list(size_t length, list_element_t elements[]) {
list_t *list = malloc(sizeof(list_t) + sizeof(list_element_t) * length);
if (!list) return NULL;
list->length = length;
if (elements && length > 0) {
memcpy(list->elements, elements, sizeof(list_element_t) * length);
}
return list;
}
// Spojí dva zoznamy do jedného tak, že prvky z druhého zoznamu sa pridajú na koniec prvého.
list_t *append_list(list_t *list1, list_t *list2) {
size_t total_len = list1->length + list2->length;
list_t *result = malloc(sizeof(list_t) + sizeof(list_element_t) * total_len);
if (!result) return NULL;
result->length = total_len;
memcpy(result->elements, list1->elements, sizeof(list_element_t) * list1->length);
memcpy(result->elements + list1->length, list2->elements, sizeof(list_element_t) * list2->length);
return result;
}
// Filtruje zoznam podľa predikátu (vracia true/false).
// Výsledkom je nový zoznam obsahujúci len tie prvky, ktoré vyhovujú podmienke.
list_t *filter_list(list_t *list, bool (*filter)(list_element_t)) {
// Dočasné pole na ukladanie filtrovanej hodnoty.
list_element_t *temp = malloc(sizeof(list_element_t) * list->length);
if (!temp) return NULL;
size_t count = 0;
for (size_t i = 0; i < list->length; ++i) {
if (filter(list->elements[i])) {
temp[count++] = list->elements[i];
}
}
list_t *filtered = new_list(count, temp);
free(temp);
return filtered;
}
// Vráti dĺžku zoznamu (počet prvkov).
size_t length_list(list_t *list) {
return list->length;
}
// Aplikuje funkciu `map` na každý prvok zoznamu a vytvorí nový zoznam výsledkov.
list_t *map_list(list_t *list, list_element_t (*map)(list_element_t)) {
list_t *result = malloc(sizeof(list_t) + sizeof(list_element_t) * list->length);
if (!result) return NULL;
result->length = list->length;
for (size_t i = 0; i < list->length; ++i) {
result->elements[i] = map(list->elements[i]);
}
return result;
}
// foldl (left fold): Redukuje zoznam zľava doprava pomocou funkcie `foldl`.
// Accumulator sa "napĺňa" v smere od začiatku zoznamu k jeho koncu.
list_element_t foldl_list(list_t *list, list_element_t initial,
list_element_t (*foldl)(list_element_t, list_element_t)) {
list_element_t acc = initial;
for (size_t i = 0; i < list->length; ++i) {
acc = foldl(acc, list->elements[i]);
}
return acc;
}
// foldr (right fold): Redukuje zoznam sprava doľava pomocou funkcie `foldr`.
// V tomto prípade sa akumulácia deje opačne od konca zoznamu k začiatku.
list_element_t foldr_list(list_t *list, list_element_t initial,
list_element_t (*foldr)(list_element_t, list_element_t)) {
list_element_t acc = initial;
// ssize_t je podpísaná verzia size_t umožní záporný index pri spätnej iterácii.
for (size_t i = list->length - 1; i >= 0; --i) {
acc = foldr(list->elements[i], acc);
}
return acc;
}
// Otočí poradie prvkov v zozname.
// Prvý sa stane posledným, druhý predposledným, atď.
list_t *reverse_list(list_t *list) {
list_t *result = malloc(sizeof(list_t) + sizeof(list_element_t) * list->length);
if (!result) return NULL;
result->length = list->length;
for (size_t i = 0; i < list->length; ++i) {
result->elements[i] = list->elements[list->length - 1 - i];
}
return result;
}
// Uvoľní pamäť alokovanú pre zoznam.
// Po tejto operácii by sa ukazovateľ už nemal používať je "visiacim".
void delete_list(list_t *list) {
free(list);
}