Linked list
- C
- C++
src/c/data-structure/linked-list.c
#include <stdio.h> // printf
#include <stdlib.h> // malloc
#include <string.h> // strcpy, strcmp
#include <assert.h> // assert
typedef struct todo_list
{
char item_name[100];
int number_of_item;
int is_important; // no boolean type in C, use 0/1 for false/true
struct todo_list *next;
} todo_list;
todo_list *create_new_item(char item_name[], int number_of_item, int is_important)
{
todo_list *list;
list = malloc(sizeof(todo_list));
assert(list);
strcpy(list->item_name, item_name);
list->number_of_item = number_of_item;
list->is_important = is_important;
list->next = NULL;
return list;
}
void print_item(todo_list *list)
{
if (list == NULL)
{
return;
}
else
{
printf("Item name: %s\n", list->item_name);
printf("Number of items: %d\n", list->number_of_item);
if (list->is_important == 0)
{
printf("Is important: false\n");
}
else
{
printf("Is important: true\n");
}
}
}
void print_list(todo_list *list)
{
if (list == NULL)
{
return;
}
else
{
print_item(list);
if (list->next == NULL)
{
return;
}
else
{
printf("\n");
print_list(list->next);
}
}
}
void insert_head(todo_list **list, todo_list *todo_item)
{
todo_item->next = *list;
*list = todo_item;
}
todo_list *search_list(todo_list *list, char item_name[])
// returns pointer to the todo item
{
if (list == NULL)
{
return NULL;
}
if (strcmp(list->item_name, item_name) == 0)
{
return list;
}
else
{
return search_list(list->next, item_name);
// if program arrives here it must return
}
}
todo_list *item_ahead(todo_list *list, char item_name[])
{
if ((list == NULL) || (list->next == NULL))
{
return (NULL);
}
if (strcmp(list->item_name, item_name) == 0)
{
return (list->next);
}
else
{
return (item_ahead(list->next, item_name));
}
}
void delete_head(todo_list **list)
{
if ((*list) != NULL)
{
todo_list *head;
head = (*list)->next;
free(*list);
*list = head;
}
}
void delete_list(todo_list **list)
{
while ((*list) != NULL)
{
delete_head(list);
}
}
int main()
{
todo_list *my_list = create_new_item("bread", 2, 0);
todo_list *milk = create_new_item("milk", 3, 1);
insert_head(&my_list, milk);
print_list(my_list);
// search
char item[] = "bread";
todo_list *my_item = search_list(my_list, item);
if (my_item == NULL)
{
printf("\n%s is not included in my list.\n", item);
}
else
{
printf("\n%s is included in my list.\n", item);
}
// item ahead
todo_list *next_item;
next_item = item_ahead(my_list, "milk");
printf("next time: %s\n", next_item->item_name);
printf("\n+++ Delete head +++\n");
delete_head(&my_list);
print_list(my_list);
printf("\n+++ Insert milk again +++\n");
milk = create_new_item("milk", 5, 0);
insert_head(&my_list, milk);
print_list(my_list);
printf("\n+++ Delete all +++\n");
delete_list(&my_list);
print_list(my_list);
return 0;
}
src/cpp/data-structure/linked-list.cpp
// linked lists are dynamic collection
// adding new item has O(1) complexity, while searching items in the list has
// O(N) cost. In comparison, inserting item in a regular array is O(N) while
// array search is O(1). If we use dynamic array instead of static array, we
// start with a specific size of the array, once we run out of space, we
// allocate a new array with double the previous size of array. We copy the
// first half of the array from previous array, and add the new element. In this
// we need to double about log(N) time for N item, so half of the item is copied
// once, quarter of item is moved twice, and so on, we will see that this is
// still a O(N) complexity to build such array.
// linked lists are used where the array size is not known compile time, and
// we do not need random access to the items in it.
// Use cases: list of navigational nodes (going from one point to another in a
// map), list of items in a shopping cart
#include <iostream>
#include <string>
using namespace std;
// this is the data structure we are going to store in our list
struct LinkedList
{
string item_name;
int number_of_item;
LinkedList *next;
};
// inserting new element to the head i.e., the new element becomes head
void add_to_head(LinkedList *&head, string new_item_name, int new_number_of_item)
{
LinkedList *new_ptr;
new_ptr = new LinkedList;
new_ptr->item_name = new_item_name;
new_ptr->number_of_item = new_number_of_item;
new_ptr->next = head;
head = new_ptr;
}
void print_linked_list(LinkedList *head)
{
LinkedList *ref_ptr = head;
cout << "List items: \n";
while (true)
{
cout << ref_ptr->item_name << " (" << ref_ptr->number_of_item << " pcs.)"
<< endl;
ref_ptr = ref_ptr->next;
if (!ref_ptr)
{
break;
}
}
}
int length_linked_list(LinkedList *head)
{
int len = 0;
LinkedList *ref_ptr = head;
while (true)
{
len += 1;
ref_ptr = ref_ptr->next;
if (!ref_ptr)
{
break;
}
}
return len;
}
void delete_head(LinkedList *&head)
// in order to delete and modify pointer we need pass by reference
{
if (head)
{
LinkedList *tmp_ptr;
tmp_ptr = head->next;
delete head;
head = tmp_ptr;
}
}
int main()
{
// let's define our head pointer first
// head pointer points to the first element of the linked list
// head pointer also used to refer to the linked list as a whole
LinkedList *head;
head = new LinkedList;
// assign the first element of the linked list
// two ways of accessing struct members via pointer dereferencing
head->item_name = "bread"; // (*head).item_name = "bread";
head->number_of_item = 3;
// if our list has only one item, the next pointer points to NULL
// in case the head pointer points to nullptr, the list is empty
// head = nullptr; // refers to empty linked list
head->next = nullptr;
cout << "Length of list = " << length_linked_list(head) << endl;
// let's add new item to the head
add_to_head(head, "water bottle", 5);
print_linked_list(head);
// add another item and print
add_to_head(head, "tissue roll", 2);
print_linked_list(head);
cout << "Length of list = " << length_linked_list(head) << endl;
delete_head(head);
print_linked_list(head);
return 0;
}