Skip to content
Snippets Groups Projects
Commit 4daf6c4b authored by Mactavish's avatar Mactavish
Browse files

add exercise for linked list

parent 484ed08c
No related branches found
No related tags found
No related merge requests found
# Linked List
Here is a small exercise that helps you understand memory management and pointer operations in C.
## Instructions
Implement a doubly linked list.
You will write an implementation of a doubly linked list with the following functions:
* `push` (*insert value at back*);
* `pop` (*remove value at back*);
* `shift` (*remove value at front*);
* `unshift` (*insert value at front*);
* `count` (*count the number of nodes in the list*);
* `delete` (*delete the node that holds the matched data*);
* etc.
To keep your implementation simple, the tests will not cover error
conditions. Specifically: `pop` or `shift` will never be called on an
empty list.
## Tips
Since linked list is a dynamic data structure, you have to use memory management functions defined in `<stdlib.h>`.
When you create a new node, you should allocate a block of memory for the node. When you delete a node or destroy the whole list, you should deallocate/free all previously allocated data.
## Testing
The included makefile can be used to create and run the tests using the following commands:
```bash
# run unit tests
make test
# check memory leaks
make memcheck
# clean all compilation files
make clean
```
## Credit
Adapted from [here](https://github.com/exercism/c/tree/main/exercises/practice/linked-list)
#include "linked_list.h"
struct list_node {
struct list_node *prev, *next;
ll_data_t data;
};
struct list {
struct list_node *first, *last;
};
struct list_node *create_node(ll_data_t data) {
// TODO: implement create_node
}
// constructs a new (empty) list
struct list *list_create(void) {
// TODO: implement list_create
}
// counts the items on a list
size_t list_count(const struct list *list) {
// TODO: implement list_count
}
// inserts item at back of a list
void list_push(struct list *list, ll_data_t item_data) {
// TODO: implement list_push
}
// removes item from back of a list
ll_data_t list_pop(struct list *list) {
// TODO: implement list_pop
}
// inserts item at front of a list
void list_unshift(struct list *list, ll_data_t item_data) {
// TODO: implement list_unshift
}
// removes item from front of a list
ll_data_t list_shift(struct list *list) {
// TODO: implement list_shift
}
// deletes a node that holds the matching data
void list_delete(struct list *list, ll_data_t data) {
// TODO: implement list_delete
}
// destroys an entire list
// list will be a dangling pointer after calling this method on it
void list_destroy(struct list *list) {
// TODO: implement list_destroy
}
#ifndef LINKED_LIST_H
#define LINKED_LIST_H
#include <stddef.h>
typedef int ll_data_t;
struct list;
// constructs a new (empty) list
struct list *list_create(void);
// counts the items on a list
size_t list_count(const struct list *list);
// inserts item at back of a list
void list_push(struct list *list, ll_data_t item_data);
// removes item from back of a list
ll_data_t list_pop(struct list *list);
// inserts item at front of a list
void list_unshift(struct list *list, ll_data_t item_data);
// removes item from front of a list
ll_data_t list_shift(struct list *list);
// deletes a node that holds the matching data
void list_delete(struct list *list, ll_data_t data);
// destroys an entire list
// list will be a dangling pointer after calling this method on it
void list_destroy(struct list *list);
// handle allocation failure
void alloaction_failure(void);
// helper function for creating bare node
struct list_node *create_node(ll_data_t data);
#endif
### If you wish to use extra libraries (math.h for instance),
### add their flags here (-lm in our case) in the "LIBS" variable.
LIBS = -lm
###
CFLAGS = -std=c99
CFLAGS += -g
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -pedantic
CFLAGS += -Werror
CFLAGS += -Wmissing-declarations
CFLAGS += -DUNITY_SUPPORT_64 -DUNITY_OUTPUT_COLOR
ASANFLAGS = -fsanitize=address
ASANFLAGS += -fno-common
ASANFLAGS += -fno-omit-frame-pointer
.PHONY: test
test: tests.out
@./tests.out
.PHONY: memcheck
memcheck: ./*.c ./*.h
@echo Compiling $@
@$(CC) $(ASANFLAGS) $(CFLAGS) ../unity/unity.c ./*.c -o memcheck.out $(LIBS)
@./memcheck.out
@echo "Memory check passed"
.PHONY: clean
clean:
rm -rf *.o *.out *.out.dSYM
tests.out: ./*.c ./*.h
@echo Compiling $@
@$(CC) $(CFLAGS) ../unity/unity.c ./*.c -o tests.out $(LIBS)
#include <stddef.h>
#include "../unity/unity.h"
#include "linked_list.h"
struct list *list = NULL;
void setUp(void)
{
list = list_create();
}
void tearDown(void)
{
if (list) {
list_destroy(list);
list = NULL;
}
}
static void test_pop_gets_element_from_the_list(void)
{
list_push(list, 7);
TEST_ASSERT_EQUAL(7, list_pop(list));
}
static void test_push_pop_respectively_add_remove_at_the_end_of_the_list(void)
{
list_push(list, 11);
list_push(list, 13);
TEST_ASSERT_EQUAL(13, list_pop(list));
TEST_ASSERT_EQUAL(11, list_pop(list));
}
static void test_shift_gets_an_element_from_the_list(void)
{
list_push(list, 17);
TEST_ASSERT_EQUAL(17, list_shift(list));
}
static void test_shift_gets_first_element_from_the_list(void)
{
list_push(list, 23);
list_push(list, 5);
TEST_ASSERT_EQUAL(23, list_shift(list));
TEST_ASSERT_EQUAL(5, list_shift(list));
}
static void test_unshift_adds_element_at_start_of_the_list(void)
{
list_unshift(list, 23);
list_unshift(list, 5);
TEST_ASSERT_EQUAL(5, list_shift(list));
TEST_ASSERT_EQUAL(23, list_shift(list));
}
static void test_pop_push_shift_and_unshift_can_be_used_in_any_order(void)
{
list_push(list, 1);
list_push(list, 2);
TEST_ASSERT_EQUAL(2, list_pop(list));
list_push(list, 3);
TEST_ASSERT_EQUAL(1, list_shift(list));
list_unshift(list, 4);
list_push(list, 5);
TEST_ASSERT_EQUAL(4, list_shift(list));
TEST_ASSERT_EQUAL(5, list_pop(list));
TEST_ASSERT_EQUAL(3, list_shift(list));
}
static void test_count_an_empty_list(void)
{
TEST_ASSERT_EQUAL(0, list_count(list));
}
static void test_count_a_list_with_items(void)
{
list_push(list, 37);
list_push(list, 1);
TEST_ASSERT_EQUAL(2, list_count(list));
}
static void test_count_is_correct_after_mutation(void)
{
list_push(list, 31);
TEST_ASSERT_EQUAL(1, list_count(list));
list_unshift(list, 43);
TEST_ASSERT_EQUAL(2, list_count(list));
list_shift(list);
TEST_ASSERT_EQUAL(1, list_count(list));
list_pop(list);
TEST_ASSERT_EQUAL(0, list_count(list));
}
static void test_popping_to_empty_does_not_break_the_list(void)
{
list_push(list, 41);
list_push(list, 59);
list_pop(list);
list_pop(list);
list_push(list, 47);
TEST_ASSERT_EQUAL(1, list_count(list));
TEST_ASSERT_EQUAL(47, list_pop(list));
}
static void test_shifting_to_empty_does_not_break_the_list(void)
{
list_push(list, 41);
list_push(list, 59);
list_shift(list);
list_shift(list);
list_push(list, 47);
TEST_ASSERT_EQUAL(1, list_count(list));
TEST_ASSERT_EQUAL(47, list_shift(list));
}
static void test_deletes_the_only_element(void)
{
list_push(list, 61);
list_delete(list, 61);
TEST_ASSERT_EQUAL(0, list_count(list));
}
static void
test_deletes_the_element_with_the_specified_value_from_the_list(void)
{
list_push(list, 71);
list_push(list, 83);
list_push(list, 79);
list_delete(list, 83);
TEST_ASSERT_EQUAL(2, list_count(list));
TEST_ASSERT_EQUAL(79, list_pop(list));
TEST_ASSERT_EQUAL(71, list_shift(list));
}
static void
test_deletes_the_element_with_the_specified_value_from_the_list_reassigns_tail(
void)
{
list_push(list, 71);
list_push(list, 83);
list_push(list, 79);
list_delete(list, 83);
TEST_ASSERT_EQUAL(2, list_count(list));
TEST_ASSERT_EQUAL(79, list_pop(list));
TEST_ASSERT_EQUAL(71, list_pop(list));
}
static void
test_deletes_the_element_with_the_specified_value_from_the_list_reassigns_head(
void)
{
list_push(list, 71);
list_push(list, 83);
list_push(list, 79);
list_delete(list, 83);
TEST_ASSERT_EQUAL(2, list_count(list));
TEST_ASSERT_EQUAL(71, list_shift(list));
TEST_ASSERT_EQUAL(79, list_shift(list));
}
static void test_deletes_the_first_of_two_elements(void)
{
list_push(list, 97);
list_push(list, 101);
list_delete(list, 97);
TEST_ASSERT_EQUAL(1, list_count(list));
TEST_ASSERT_EQUAL(101, list_pop(list));
}
static void test_deletes_the_second_of_two_elements(void)
{
list_push(list, 97);
list_push(list, 101);
list_delete(list, 101);
TEST_ASSERT_EQUAL(1, list_count(list));
TEST_ASSERT_EQUAL(97, list_pop(list));
}
static void
test_delete_does_not_modify_the_list_if_the_element_is_not_found(void)
{
list_push(list, 89);
list_delete(list, 103);
TEST_ASSERT_EQUAL(1, list_count(list));
}
static void test_deletes_only_the_first_occurrence(void)
{
list_push(list, 73);
list_push(list, 9);
list_push(list, 9);
list_push(list, 107);
list_delete(list, 9);
TEST_ASSERT_EQUAL(3, list_count(list));
TEST_ASSERT_EQUAL(107, list_pop(list));
TEST_ASSERT_EQUAL(9, list_pop(list));
TEST_ASSERT_EQUAL(73, list_pop(list));
}
int main(void)
{
UnityBegin("test_linked_list.c");
RUN_TEST(test_pop_gets_element_from_the_list);
RUN_TEST(test_push_pop_respectively_add_remove_at_the_end_of_the_list);
RUN_TEST(test_shift_gets_an_element_from_the_list);
RUN_TEST(test_shift_gets_first_element_from_the_list);
RUN_TEST(test_unshift_adds_element_at_start_of_the_list);
RUN_TEST(test_pop_push_shift_and_unshift_can_be_used_in_any_order);
RUN_TEST(test_count_an_empty_list);
RUN_TEST(test_count_a_list_with_items);
RUN_TEST(test_count_is_correct_after_mutation);
RUN_TEST(test_popping_to_empty_does_not_break_the_list);
RUN_TEST(test_shifting_to_empty_does_not_break_the_list);
RUN_TEST(test_deletes_the_only_element);
RUN_TEST(test_deletes_the_element_with_the_specified_value_from_the_list);
RUN_TEST(
test_deletes_the_element_with_the_specified_value_from_the_list_reassigns_tail);
RUN_TEST(
test_deletes_the_element_with_the_specified_value_from_the_list_reassigns_head);
RUN_TEST(test_deletes_the_first_of_two_elements);
RUN_TEST(test_deletes_the_second_of_two_elements);
RUN_TEST(test_delete_does_not_modify_the_list_if_the_element_is_not_found);
RUN_TEST(test_deletes_only_the_first_occurrence);
return UnityEnd();
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment