Added linked list impl, not fully tested yet.
This commit is contained in:
parent
c5b4193e56
commit
8d80b24adc
|
@ -0,0 +1,193 @@
|
|||
#include <malloc.h>
|
||||
#include "linked_list.h"
|
||||
|
||||
//internal
|
||||
|
||||
linked_list_node* _get_by_index(linked_list_node *head, int index)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
if(index <= 0 || head == NULL)
|
||||
return head;
|
||||
head = head->next;
|
||||
index--;
|
||||
}
|
||||
}
|
||||
|
||||
linked_list_node* _get_by_element(linked_list_node* head, void* data, int(*compare)(int*,int*))
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
if(head == NULL || compare(data,head->data) == 0)
|
||||
return head;
|
||||
head = head->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
linked_list_node* _create()
|
||||
{
|
||||
linked_list_node* node = (linked_list_node*)malloc(sizeof(linked_list_node));
|
||||
node->data = NULL;
|
||||
node->prev = NULL;
|
||||
node->next = NULL;
|
||||
return node;
|
||||
}
|
||||
|
||||
void _delete(linked_list* list, linked_list_node* node)
|
||||
{
|
||||
if(list != NULL && node != NULL)
|
||||
{
|
||||
//check if itself is head
|
||||
if(list->head == node)
|
||||
{
|
||||
list->head = node->next;
|
||||
}
|
||||
//check if itself is tail
|
||||
if(list->tail == node)
|
||||
{
|
||||
list->tail = node->prev;
|
||||
}
|
||||
if (node->prev != NULL)
|
||||
node->prev->next = node->next;
|
||||
if (node->next != NULL)
|
||||
node->next->prev = node->prev;
|
||||
list->size--;
|
||||
free(node);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//interface
|
||||
linked_list* linked_list_create()
|
||||
{
|
||||
linked_list* list = (linked_list*)malloc(sizeof(linked_list));
|
||||
list->size = 0;
|
||||
list->tail = NULL;
|
||||
list->head = NULL;
|
||||
return list;
|
||||
}
|
||||
|
||||
void linked_list_free(linked_list* list, void(*delete_data)(void*))
|
||||
{
|
||||
if(list == NULL)
|
||||
return;
|
||||
linked_list_node* head = list->head;
|
||||
while(head != NULL)
|
||||
{
|
||||
linked_list_node* temp = head;
|
||||
head = head->next;
|
||||
if(delete_data != NULL)
|
||||
delete_data(temp->data);
|
||||
free(temp);
|
||||
}
|
||||
free(list);
|
||||
return;
|
||||
}
|
||||
|
||||
void linked_list_insert(linked_list * list, void* data)
|
||||
{
|
||||
if(list == NULL)
|
||||
return;
|
||||
linked_list_node* node = _create();
|
||||
node->data = data;
|
||||
if(list->tail != NULL)
|
||||
{
|
||||
//already elements in the list
|
||||
//guaranteed that list->next == NULL
|
||||
node->prev = list->tail;
|
||||
list->tail->next = node;
|
||||
list->tail = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
//no element case
|
||||
list->tail = node;
|
||||
list->head = node;
|
||||
}
|
||||
list->size++;
|
||||
return;
|
||||
}
|
||||
|
||||
void linked_list_insert_at(linked_list * list, int position, void* data)
|
||||
{
|
||||
if(list != NULL && position >= 0 && position <= list->size)
|
||||
{
|
||||
linked_list_node* target = _get_by_index(list->head,position);
|
||||
if(target == NULL)
|
||||
{
|
||||
//tail case
|
||||
linked_list_insert(list, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
//head or normal case
|
||||
linked_list_node* node = _create();
|
||||
node->data = data;
|
||||
if (list->head == target) {
|
||||
list->head = node;
|
||||
}
|
||||
node->prev = target->prev;
|
||||
node->next = target;
|
||||
if (target->prev != NULL)
|
||||
target->prev->next = node;
|
||||
target->prev = node;
|
||||
list->size++;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void* linked_list_get(linked_list * list, int index)
|
||||
{
|
||||
if(list == NULL || list->head == NULL || index < 0 || list->size <= index)
|
||||
return NULL;
|
||||
linked_list_node* node = _get_by_index(list->head, index);
|
||||
return node == NULL ? NULL : node->data;
|
||||
}
|
||||
|
||||
void linked_list_delete(linked_list * list, void* data, int(*compare)(int*,int*))
|
||||
{
|
||||
if(list == NULL || list->head == NULL || compare == NULL)
|
||||
return;
|
||||
linked_list_node* node = _get_by_element(list->head,data,compare);
|
||||
_delete(list,node);
|
||||
return;
|
||||
}
|
||||
|
||||
void linked_list_delete_at(linked_list * list, int index)
|
||||
{
|
||||
if(list == NULL || list->head == NULL || index < 0 || list->size <= index)
|
||||
return;
|
||||
linked_list_node* node = _get_by_index(list->head, index);
|
||||
_delete(list,node);
|
||||
return;
|
||||
}
|
||||
|
||||
// iterator
|
||||
linked_list_iterator* linked_list_create_iterator(linked_list* list)
|
||||
{
|
||||
if(list == NULL)
|
||||
return NULL;
|
||||
linked_list_iterator* it = (linked_list_iterator*)malloc(sizeof(linked_list_iterator));
|
||||
it->current = list->head;
|
||||
return it;
|
||||
}
|
||||
|
||||
void linked_list_delete_iterator(linked_list_iterator* it)
|
||||
{
|
||||
free(it);
|
||||
return;
|
||||
}
|
||||
|
||||
void linked_list_prev(linked_list_iterator* it)
|
||||
{
|
||||
it->current = it->current->prev;
|
||||
return;
|
||||
}
|
||||
|
||||
void linked_list_next(linked_list_iterator* it)
|
||||
{
|
||||
it->current = it->current->next;
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef _LINKED_LIST_H_
|
||||
#define _LINKED_LIST_H_
|
||||
typedef struct _linked_list_node
|
||||
{
|
||||
struct _linked_list_node* prev;
|
||||
struct _linked_list_node* next;
|
||||
void* data;
|
||||
} linked_list_node;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
linked_list_node* head;
|
||||
linked_list_node* tail;
|
||||
int size;
|
||||
} linked_list;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
linked_list_node* current;
|
||||
} linked_list_iterator;
|
||||
|
||||
linked_list* linked_list_create();
|
||||
|
||||
void linked_list_insert(linked_list * list, void* data);
|
||||
|
||||
void linked_list_insert_at(linked_list * list, int position, void* data);
|
||||
|
||||
void* linked_list_get(linked_list * list, int index);
|
||||
|
||||
void linked_list_delete(linked_list * list, void* data, int(*compare)(int*,int*));
|
||||
|
||||
void linked_list_delete_at(linked_list * list, int index);
|
||||
|
||||
linked_list_iterator* linked_list_create_iterator(linked_list* list);
|
||||
|
||||
void linked_list_delete_iterator(linked_list_iterator* it);
|
||||
|
||||
void linked_list_prev(linked_list_iterator* it);
|
||||
|
||||
void linked_list_next(linked_list_iterator* it);
|
||||
|
||||
void linked_list_free(linked_list* list, void(*delete_data)(void*));
|
||||
|
||||
#endif
|
|
@ -0,0 +1,99 @@
|
|||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include "linked_list.h"
|
||||
|
||||
void print_list(linked_list* list)
|
||||
{
|
||||
linked_list_iterator* it = linked_list_create_iterator(list);
|
||||
it->current = list->tail;
|
||||
while(it->current)
|
||||
{
|
||||
printf("%lu ", (unsigned long)it->current->data);
|
||||
linked_list_prev(it);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void insert_test(void)
|
||||
{
|
||||
printf("insert test\n");
|
||||
linked_list* list;
|
||||
//empty list at test
|
||||
list = linked_list_create();
|
||||
linked_list_insert_at(list,0,(void*)2);
|
||||
assert(list->size == 1 && list->head == list->tail && (int)list->head->data == 2);
|
||||
print_list(list);
|
||||
|
||||
//tail test
|
||||
linked_list_insert_at(list,1,(void*)3);
|
||||
assert(list->size == 2 && (int)list->tail->data == 3);
|
||||
print_list(list);
|
||||
|
||||
//head test
|
||||
linked_list_insert_at(list,0,(void*)1);
|
||||
assert(list->size == 3 && (int)list->head->data == 1);
|
||||
print_list(list);
|
||||
|
||||
//invalid index test
|
||||
linked_list_insert_at(list,4,(void*)1);
|
||||
assert(list->size == 3 && (int)list->head->data == 1 && (int)list->tail->data == 3);
|
||||
print_list(list);
|
||||
|
||||
//normal test
|
||||
linked_list_insert_at(list,1,(void*)5);
|
||||
assert(list->size == 4 && (int)list->head->next->data == 5 && (int)list->head->next->next->data == 2);
|
||||
print_list(list);
|
||||
|
||||
linked_list_free(list,NULL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void delete_test(void)
|
||||
{
|
||||
printf("delete test\n");
|
||||
linked_list* list;
|
||||
//empty list at test
|
||||
list = linked_list_create();
|
||||
linked_list_insert(list,(void*)1);
|
||||
linked_list_insert(list,(void*)2);
|
||||
linked_list_insert(list,(void*)3);
|
||||
linked_list_insert(list,(void*)4);
|
||||
linked_list_insert(list,(void*)5);
|
||||
|
||||
//head test
|
||||
linked_list_delete_at(list,0);
|
||||
assert(list->size == 4 && (int)list->head->data == 2);
|
||||
print_list(list);
|
||||
|
||||
//tail test
|
||||
linked_list_delete_at(list,list->size-1);
|
||||
assert(list->size == 3 && (int)list->tail->data == 4);
|
||||
print_list(list);
|
||||
|
||||
//normal test
|
||||
linked_list_delete_at(list,1);
|
||||
assert(list->size == 2 && (int)list->head->data == 2 && (int)list->head->next->data==4);
|
||||
print_list(list);
|
||||
|
||||
//invalid index test
|
||||
linked_list_delete_at(list,2);
|
||||
assert(list->size == 2 && (int)list->head->data == 2 && (int)list->head->next->data==4);
|
||||
print_list(list);
|
||||
|
||||
//delete last test
|
||||
linked_list_delete_at(list,0);
|
||||
linked_list_delete_at(list,0);
|
||||
assert(list->size == 0 && list->head == NULL && list->tail == NULL);
|
||||
|
||||
linked_list_free(list,NULL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
insert_test();
|
||||
delete_test();
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue