Is it possible to build a linked list without the help of self referential structure? I.e. like this just using a pointer:
struct list{
int data;
int *nxt;
};
instead of
struct list{
int data;
struct list *nxt;
};
Is it possible to build a linked list without the help of self referential structure? I.e. like this just using a pointer:
struct list{
int data;
int *nxt;
};
instead of
struct list{
int data;
struct list *nxt;
};
Another approach is to use parallel arrays as your "heap"1, with one array containing your data (whether a scalar or a struct) and another to store the index of the next "node" in the list, like:
int data[N];
int next[N];
You'll need two "pointers" - one to point to the first element in the list, and one to point to the first available "node" in your "heap".
int head;
int free;
You'll initialize all the elements in the "next" array to "point" to the next element, except for the last element which points to "null":
for ( int i = 1; i < N-1; i++ )
next[i-1] = i;
next[N-1] = -1;
free = 0; // first available "node" in the heap
head = -1; // list is empty, head is "null"
Inserting a new element in the list looks something like this (assuming an ordered list):
if ( free != -1 )
{
int idx = free; // get next available "node" index;
free = next[free]; // update the free pointer
data[idx] = newValue;
next[idx] = -1;
if ( head == -1 )
{
head = idx;
}
else if ( data[idx] < data[head] )
{
next[idx] = head;
head = idx;
}
else
{
int cur = head;
while ( next[cur] != -1 && data[idx] >= data[next[cur]] )
cur = next[cur];
next[idx] = next[cur];
next[cur] = idx;
}
}
Deleting an element at idx
is pretty straightforward:
int cur = head;
while ( next[cur] != idx && next[cur] != -1 )
cur = next[cur];
if ( next[cur] == idx )
{
next[cur] = next[idx]; // point to the element following idx
next[idx] = free; // add idx to the head of the free list
free = idx;
}
Advantages of this approach:
Disadvantages:
static
, meaning your binary may have a large footprint;-1
as "null" means you have to use a signed type for your indices, which reduces the number of available elements for a given array type. You could certainly use 0
as "null" and count all your indices from 1
; this allows you to use unsigned types like size_t
for your indices, meaning you can make your arrays pretty much as big as the system will allow. It's just that 0
is a valid array index whereas -1
(usually) isn't, which is why I chose it for this example.
You might have a look at how linked lists are implemented in the Linux kernel.
Compared to the classical linked lists:
struct my_list{
void *myitem;
struct my_list *next;
struct my_list *prev;
};
using a linked list in the linux kernel looks like:
struct my_cool_list{
struct list_head list; /* kernel's list structure */
int my_cool_data;
};
Yes, it's possible.
What you're proposing is type punning, and you'll probably get away with it with most compilers on most platforms, but there's not a single good reason to do it in the first place and many good reasons not to.
Sure. You could use
void *
instead ofstruct list *
as yournxt
member. For example:Alternatively, if you're prepared to build in a guarantee that the nodes of the list will be stored into an array (which is great for cache locality and insertion speed), you could use a
size_t
.If your implementation provides
uintptr_t
(from<stdint.h>
), you could merge these two types into one: