Skip to content

Commit 8d45509

Browse files
authored
Forward list optimization (#53)
Add a tail pointer which is either NULL or points to the back of the list. This improves the performance when adding to the back of the list many times in a row.
1 parent 2b75351 commit 8d45509

3 files changed

Lines changed: 36 additions & 8 deletions

File tree

src/forward_list.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ struct internal_forward_list {
2828
size_t bytes_per_item;
2929
int item_count;
3030
struct node *head;
31+
struct node *tail;
3132
};
3233

3334
struct node {
@@ -57,6 +58,7 @@ forward_list forward_list_init(const size_t data_size)
5758
init->bytes_per_item = data_size;
5859
init->item_count = 0;
5960
init->head = NULL;
61+
init->tail = NULL;
6062
return init;
6163
}
6264

@@ -113,9 +115,15 @@ static struct node *forward_list_get_node_at(forward_list me, const int index)
113115
{
114116
struct node *traverse = me->head;
115117
int i;
118+
if (me->tail && index == me->item_count - 1) {
119+
return me->tail;
120+
}
116121
for (i = 0; i < index; i++) {
117122
traverse = traverse->next;
118123
}
124+
if (!traverse->next) {
125+
me->tail = traverse;
126+
}
119127
return traverse;
120128
}
121129

@@ -175,6 +183,9 @@ int forward_list_add_at(forward_list me, const int index, void *const data)
175183
struct node *const traverse = forward_list_get_node_at(me, index - 1);
176184
add->next = traverse->next;
177185
traverse->next = add;
186+
if (!add->next) {
187+
me->tail = add;
188+
}
178189
}
179190
me->item_count++;
180191
return 0;
@@ -238,17 +249,15 @@ int forward_list_remove_at(forward_list me, const int index)
238249
me->head = temp->next;
239250
free(temp->data);
240251
free(temp);
241-
} else if (index == me->item_count - 1) {
242-
struct node *const traverse = forward_list_get_node_at(me, index - 1);
243-
free(traverse->next->data);
244-
free(traverse->next);
245-
traverse->next = NULL;
246252
} else {
247253
struct node *const traverse = forward_list_get_node_at(me, index - 1);
248254
struct node *const backup = traverse->next;
249255
traverse->next = traverse->next->next;
250256
free(backup->data);
251257
free(backup);
258+
if (!backup->next) {
259+
me->tail = NULL;
260+
}
252261
}
253262
me->item_count--;
254263
return 0;

src/list.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,11 +140,10 @@ static struct node *list_get_node_from_tail(list me, const int index)
140140
*/
141141
static struct node *list_get_node_at(list me, const int index)
142142
{
143-
if (index <= me->item_count / 2) {
143+
if (index < me->item_count / 2) {
144144
return list_get_node_from_head(me, index);
145-
} else {
146-
return list_get_node_from_tail(me, index);
147145
}
146+
return list_get_node_from_tail(me, index);
148147
}
149148

150149
/**

tst/forward_list.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,25 @@ static void test_basic(void)
150150
assert(!forward_list_destroy(me));
151151
}
152152

153+
static void test_add_back(void)
154+
{
155+
int i;
156+
forward_list me = forward_list_init(sizeof(int));
157+
assert(me);
158+
for (i = 1; i < 10000; i++) {
159+
int get = 0xdeadbeef;
160+
forward_list_add_last(me, &i);
161+
forward_list_get_last(&get, me);
162+
assert(get == i);
163+
if (i % 5 == 0) {
164+
forward_list_remove_last(me);
165+
forward_list_get_last(&get, me);
166+
assert(get == i - 1);
167+
}
168+
}
169+
assert(!forward_list_destroy(me));
170+
}
171+
153172
static void test_init_out_of_memory(void)
154173
{
155174
fail_malloc = 1;
@@ -264,6 +283,7 @@ void test_forward_list(void)
264283
{
265284
test_invalid_init();
266285
test_basic();
286+
test_add_back();
267287
test_init_out_of_memory();
268288
test_add_first_out_of_memory();
269289
test_add_at_out_of_memory();

0 commit comments

Comments
 (0)