My question is very simple, can one using C++, implement a link-list data structure without using pointers (next nodes)? To further qualify my question, I\'m mean can one cr
While I'm not sure just what the context behind your question is, if you do a little out of the box thinking I'm sure you can.
DVK suggested arrays, which is quite true, but arrays are simply thin wrappers around pointer arithmetic.
How about something entirely different: use the filesystem to do the storage for you!
for example, the file
/linked-list/1
contains the data:
Data 1!
5
and /linked-list/5
is the next node in the list...
If you're willing to hack enough, anything is possible :-p
Note that said implementation's complexity / speed is entirely dependent on your filesystem (i.e. it's not necessarily O(1) for everything)
You could make a linked-list using references, but that would probably be more complicated than necessary. you would have to implement an immutable linked-list which would be complicated without a built in garbage collector.
Wow, NO? Surely you guys are not serious?
All a linked list needs is a link. Nothing says it has to be a pointer. Consider the case of wanting to store a linked list in shared mem, where the base addr is dynamic? Answer is simply, store the link as a Offset from the start of the mem block, (or some other constant) and redefine the iterator to do the actual logic of adding the base addr. Obviously, insert etc would have to be changed as well.
But fairly trivial!
Allan
Yes you can, it is not necessary to use pointers for a link list. It is possible to link a list without using pointers. You can statically allocate an array for the nodes, and instead of using next and previous pointer, you can just use indexes. You can do that to save some memory, if your link list is not greater than 255 for example, you can use 'unsigned char' as index (referencing C), and save 6 bytes for next and previous indications.
You may need this kind of array in embedded programming, since memory limitations can be troublesome sometimes.
Also keep in mind that your link list nodes will not necessary be contiguous in the memory.
Let's say your link list will have 60000 nodes. Allocating a free node from the array using a linear search should be inefficient. Instead, you can just keep the next free node index everytime:
Just initialize your array as each next index shows the current array index + 1, and firstEmptyIndex = 0.
When allocating a free node from the array, grab the firstEmptyIndex node, update the firstEmptyIndex as next index of the current array index (do not forget to update the next index as Null or empty or whatever after this).
When deallocating, update the next index of the deallocating node as firstEmptyIndex, then do firstEmptyIndex = deallocating node index.
In this way you create yourself a shortcut for allocating free nodes from the array.
Sure, if you don't mind the linked list having a maximum size, you could statically allocate an array of list nodes, and then use integer indices into the array as your "previous" and "next" values for each node, rather than pointers. I've done in this in the past to save a bit of memory (since an integer can be either 2 or 4 bytes, whereas on a 64-bit system a pointer will be 8 bytes)
I suppose using references is cheating and, technically, this causes UB, but here you go:
// Beware, un-compiled code ahead!
template< typename T >
struct node;
template< typename T >
struct links {
node<T>& prev;
node<T>& next;
link(node<T>* prv, node<T>* nxt); // omitted
};
template< typename T >
struct node {
T data;
links<T> linked_nodes;
node(const T& d, node* prv, node* nxt); // omitted
};
// technically, this causes UB...
template< typename T >
void my_list<T>::link_nodes(node<T>* prev, node<T>* next)
{
node<T>* prev_prev = prev.linked_nodes.prev;
node<T>* next_next = next.linked_nodes.next;
prev.linked_nodes.~links<T>();
new (prev.linked_nodes) links<T>(prev_prev, next);
next.linked_nodes.~links<T>();
new (next.linked_nodes) links<T>(next, next_next);
}
template< typename T >
void my_list<T>::insert(node<T>* at, const T& data)
{
node<T>* prev = at;
node<T>* next = at.linked_nodes.next;
node<T>* new_node = new node<T>(data, prev, next);
link_nodes(prev, new_node);
link_nodes(new_node, next);
}