Intro:
There are usually two ways to use linked lists: with a root element and without.
Without a root, your list pointer is NULL when the list is empty:
node *list;
...
if (list == NULL) { /* empty list */ }
With root, there is always one element. But it can be used in two ways:
Either simply to provide a pointer to the first element.
node *root;
...
if (root->next == NULL) { /* empty list */ }
Or to have the last element link back to the root to form a cycle. This concept has the advantage that the "next" element is never NULL and you thus don't need to check for it. In this case, the list is empty if the root points back to itself.
node *root;
...
if (root->next == root) { /* empty list */ }
Answer:
Now, according to your description, you have allocated a node. This either means you want the "root" approach (second or third example). But if you want to go with the first variant, you must not allocate the node, since it doesn't hold data.
For the "root" approach, you indeed have one (and only one) node that doesn't hold data. But for simple linked lists, all nodes must contain data.
Answer from DarkDust on Stack OverflowIntro:
There are usually two ways to use linked lists: with a root element and without.
Without a root, your list pointer is NULL when the list is empty:
node *list;
...
if (list == NULL) { /* empty list */ }
With root, there is always one element. But it can be used in two ways:
Either simply to provide a pointer to the first element.
node *root;
...
if (root->next == NULL) { /* empty list */ }
Or to have the last element link back to the root to form a cycle. This concept has the advantage that the "next" element is never NULL and you thus don't need to check for it. In this case, the list is empty if the root points back to itself.
node *root;
...
if (root->next == root) { /* empty list */ }
Answer:
Now, according to your description, you have allocated a node. This either means you want the "root" approach (second or third example). But if you want to go with the first variant, you must not allocate the node, since it doesn't hold data.
For the "root" approach, you indeed have one (and only one) node that doesn't hold data. But for simple linked lists, all nodes must contain data.
I'd keep it simple.
Check the head pointer - if it is NULL, there's no entry in the list.
int isEmpty( node * list )
{
if( !list )
return 1;
return 0;
}
Videos
First of all you don't need double pointer. Initialization with NULL is important here. (Denotes the empty list).
SortedList *list = NULL;
This has the benefit that now if you want to make changes to it pass it's address.
func(&list);
And checking the empty list would be
void func(SortedList **list){
if( *list == NULL )
/* empty */
}
This is usually the way lists are implemented.
In your case you simply allocated to a local variable and instead of returning the memory address you have overwritten the pointer's value with NULL - there is memory leak in the code.
With your code it will be something like. Yes all that the initialization does is assigning it to NULL. This is one easy way out towards checking the NULL. At the very beginning making it NULL
basically denotes that list is empty.(which is the case generally).
list is a pointer to a pointer. The actual list is in the value it points to, so you need to dereference it.
An empty list is just a null pointer, so you don't need to allocate anything in init().
void init(SortedList** list)
{
*list=NULL;
printf("%p\n", *list);
}
void isEmpty(SortedList** list)
{
printf("%p\n", *list);
if(*list == NULL) printf("List is empty\n");]
}
And in the main function, you don't need a double pointer, you use the & (address-of) operator to get the address of a pointer variable.
int main()
{
SortedList *list;
init(&list);
printf("Initialization with succes\n");
isEmpty(&list);
return 0;
}
You only really need double pointers for functions that modify the list. So you could use an ordinary pointer for isEmpty:
void isEmpty(SortedList* list)
{
printf("%p\n", list);
if(list == NULL) printf("List is empty\n");]
}
and then call it as:
isEmpty(list);
But it's probably simplest to be consistent across all your functions.
Hello, I've been making a linked list, and talking about it with my dad too, he insists that you should be allowed to make an empty linked list, but I don't think there should be, since there's "no reason to store nothing."
Thoughts?
Edit: feel free to continue posting your thoughts, but after some thought, I'll reconsider allowing an empty list, since having the end user work around this issue would probably make it overall more work. Thank you very much for your input though! I'll let my dad know most of you agree with him 😂
Edit 2: alrighty, I've thought about it, I'll definitely be implementing the support for an empty linked list (though I'll have to rewrite a large chunk of code, rip lol) I definitely enjoyed talking with you guys, and I look forward to finally posting my implementation.
This completely depends on the implementation. However, this typically can be done very quickly by checking to see if the first node exists/has contents/etc.
Yes. The reason is: sometimes we use the iterator to insert element, it would be very uncomfortable (or impossible) to handle the number of the elements over the iterators. This is the reason why many STL implementation has linear time for size_t size(void) function. bool empty(void) is an effective way to check if the list is empty and it has constant time.
Just to note: when you use STL prefer to use bool empty(void) against size_t size(void). More info in: Meyers: Effective STL.
The function is simple:
bool empty( void ) const
{
return ( this->begin() == this->end() );
}
In your case:
bool empty( void ) const
{
return ( this->head == 0 );
}
A linked list is empty when it contains no nodes. Typically, you access a linked list via a pointer to the head -- first node -- of the list. If there are no nodes, the head pointer is null and the list is empty.
It looks like you've written your own linked list for some reason, maybe an assignment?
You could probably just make Product* next point to this when it's empty. So if next == this then the list is empty. Alternatively, if the List's head node is null then the list is empty.
In the future I would recommend splitting your linked list implementation from your Product code. You should be able to have a List<Product>, rather than Product being both a list and something else at the same time.
So if you only have the head pointer then you need to traverse it until the end node.
First you should check that the head_ptr exists.
if (head_ptr == nullptr)
// assign your first node to the head pointer
otherwise you need to get to the end of the list. Since this is homework, how about some psuedo code.
make a node of interest, call it end_node
while we are not at the end //How can we tell if we are at the end (hint you assign the
// next in your add already check for this)
move to the next node (interest_node = interest_node->next)
end
Now we are at the end node so you can just add your new node on the end.
Hint (you may want to check for broken linked lists ie. circular links.
I think you need something like
head_ptr->next = my_first_node;
inside "add_node" function
this will make your head_ptr add a "real" new node.
and for your question (loop before add_node)
just doing something like
while(head_ptr != nullptr){
... //your code (maybe you can backup the last node in here?)
// write code for head ptr = next node
}
But remember to backup your "real" head_ptr before you assign "next" to your head_ptr.
Otherwise you can't get it back