RE: [C++] Doubly-Linked Lists - Data Structures 09-05-2015, 01:31 AM
#4
In C++ typically it's not a great idea to use a linked-list, in C it's an easy way to chain things together, but linked-lists in general are very bad for performance. Additionally, they also make it more prone to make tons of cache-misses, and this is even more true the larger the list is. Aside from the allocations too, you have to store pointers bidirectionally so that you can make proper manipulations to the web of data. Linked lists are probably 100 times slower in some cases than a vector because of this. Sure, with a vector you have to move a lot of elements within an allocated space but caches are very efficient at doing this. Using pointers in the way a linked list uses them is like poison to caches.
You can only use realloc() on memory allocated on the heap with a function like malloc() though, just to clarify.
Other advantages of a vector:
- It takes care of memory for you, and as of C++11 all STL containers utilize RAII to ensure safe memory management even in the case of an exception
- C++11 - std::vector<bool> is specialized to essentially store each element as a bit in size
edit: Don't forget the semi-colon at the end of your struct
Why do you keep nodes for front and back though? Just globally too? That may avoid the requirement to linear traverse the linked list for each deletion and insertion, but you have to do this anyways if you want your linked list to be sorted in some way anyways or if you're deleting specific data or searching for something.
Btw, for your deletion function:
These checks are not as useful because you should know if they are the front or the back of the linked list simply by the node's contained pointers, you shouldn't have to compare the pointer to the current node at all. If prev is null when you compare the id, then you know that it should be the front, and reversely, if the next pointer is null, then you should automatically be able to deduce that it's the end of the linked list.
i.e. Here's how I'd write it.
I'd also put the front and rear pointers into an object of its own, that way you don't have to rely on these being global, and you can pass a pointer to the struct containing these 2 pointers to modify them within the function if your strategy is to keep a pointer to the start and end of the doubly linked list.
Quote:3. Whether it's a static or a dynamic allocation, the size of that array needs to be defined. Whether the size is constant or defined on run time, once the array is allocated then you simply have to use it the way it is, now ofcorse you can use realloc(which isn't so efficient) or create a second one and copy to it the bytes of the first one then delete/free the first one and keep using the second one (which is something, I consider, dumb since it requires a lot of operations).
You can only use realloc() on memory allocated on the heap with a function like malloc() though, just to clarify.
Other advantages of a vector:
- It takes care of memory for you, and as of C++11 all STL containers utilize RAII to ensure safe memory management even in the case of an exception
- C++11 - std::vector<bool> is specialized to essentially store each element as a bit in size
edit: Don't forget the semi-colon at the end of your struct
Code:
struct NODE {
int id;
char username;
NODE *next = NULL;
NODE *prev = NULL;
}; <---Why do you keep nodes for front and back though? Just globally too? That may avoid the requirement to linear traverse the linked list for each deletion and insertion, but you have to do this anyways if you want your linked list to be sorted in some way anyways or if you're deleting specific data or searching for something.
Btw, for your deletion function:
Code:
if (curr == front)
else if (curr == rear)These checks are not as useful because you should know if they are the front or the back of the linked list simply by the node's contained pointers, you shouldn't have to compare the pointer to the current node at all. If prev is null when you compare the id, then you know that it should be the front, and reversely, if the next pointer is null, then you should automatically be able to deduce that it's the end of the linked list.
i.e. Here's how I'd write it.
Code:
void delete_item( int id)
{
NODE *curr = front;
while (curr)
{
if (curr->id == id)
{
if (!curr->prev) front = curr->next;
else if (!curr->next) rear = curr->prev;
curr->prev->next = curr->next;
curr->next->prev = cur->prev;
delete curr;
return;
}
curr = curr->next;
}
}I'd also put the front and rear pointers into an object of its own, that way you don't have to rely on these being global, and you can pass a pointer to the struct containing these 2 pointers to modify them within the function if your strategy is to keep a pointer to the start and end of the doubly linked list.



![[+]](https://sinister.li/images/modern/collapse_collapsed.png)