I'm new to C and have a question.
How would I check if a linked list is empty?
I have a struct _node
typedef struct _node{
int data;
struct _node *next;
}node;
If I have initialized node *list, but didn't do anything to it (i.e didn't assign list->data a value), how would I check if it's empty?
I tried if (node == NULL){break} but didn't work.
Thanks for the help!
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.
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;
}
Sometimes when you create a variable, C will zero out all the data for you. Other times, the variable will contain garbage. You need to learn the rules that govern this, but as a beginner, you should simply be certain always to initialize your variables explicitly.
For a linked list, when you append a node to a list, you should always be certain to set a NULL into the next pointer, so that the list will be properly terminated.
Your linked list should have a "head" pointer. If the head is set to NULL then you have a zero-length linked list; if the head has any value other than NULL you must have at least one node in the linked list, so the list must have length of at least 1.
So, as long as you have been careful about initializing your head pointer to NULL you can trivially tell whether the list is empty by checking to see if the head pointer is NULL.
But your question was really about the data member variable. There will always be some sort of value in there. As I said, sometimes C will set it to zero for you, but other times it will be unpredictable garbage (a value that could be any integer value). You need to initialize that to a sensible default when you allocate a new node. For example, the valid values of data might all be greater than zero, so you might set data to zero to indicate that it is currently empty.
You can write a simple loop that traverses your linked list and checks each data member, and return true if it finds any data that is not zero (or whatever special value flags that it is unused). It should return false if it finds only default data or if the list is zero length.
Its better to have a header node when building your linked list. Then you can add nodes to build the list. Let that list variable be your header node. Then to check if your linked list is empty, use this:
typedef struct _node{
int data;
struct _node *next;
}*node;
and then instantiate
node list;
and to check the linked list is empty use
if((list->next)==null)
{
break;
}
Related
I am coding a spell checker which loads a dictionary into memeory and checks a given text for misspelled words. To implement this i would like to use a hash table. To handle collisions i'll use linked lists. Every word from the dictionary gets added to the beginning of the linked list of the corresponding hash.
I created an array of pointers to a struct called node. Here's my code for this:
typedef struct node
{
char word[LENGHT + 1];
struct node* next;
}
node;
node* table[HASHTABLE_SIZE];
My question is: Is it possible to check if table[x] is already pointing to a node in order to know if node.next should point to the rest of a linked list or should be NULL because its the first element in the linked list?
Since you are creating a hash table of size HASH_TABLE_SIZE which means there are HASH_TABLE_SIZE no. of liked list.Initially all linked list's head will be pointing to NULL. Inorder to know whether the table at index x is already having some element you just need to check whether the head at index x in the hash table in NULL or not.
if(table[x])
//head is already created for the linked list having x as index
else
//head is NULL append the first node in this linked list at index x.And make this node new head
if (table[0] == NULL)
// Create memory & allocate everything
Note that you can also do
if (table[0]->next == NULL)
// assign next
Or even in C
if (!table[0]) // If table[0] does not exist
Let's say I have the following struct:
struct object {
char *name;
struct object *next;
};
Using that I can easily create a table as a described in K&R C book. And remove all the objects by that:
object *object_destroy(object *obj)
{
if (obj != NULL) {
object_destroy(obj->next);
free(obj->name);
free(obj);
obj = NULL;
}
}
But what I want is to remove one of the objects in table, saving all the others. I really have no idea how to implement that, because just free() that object is won't work: the objects after it will be permamently lost. I can't obj_to_remove = obj_to_remove->next too, because after that I will lose all the objects before that object.
So can you point me out what I am missing? Thanks.
You are effectively attempting to delete a single node from a singly linked list (as opposed to a doubly-linked-list, or a circular list, also known as a ring buffer).
Please refer to the references below for more information on the concept of a singly linked list. In short, you:
Start at the first node in the list (the head node).
Cycle through the list one node at a time, keeping a pointer to the previously accessed node, until you find the node you want to delete.
Point the previous node in the list to the one ahead of the current/found node.
3.1. If there is no node afterwards (we are at the end of the list), set to NULL.
3.2. If the head/first node was the one found, set the head node to the second node in the list.
Delete the elements inside the node if the node has been found.
Delete the current node itself.
The second reference will be very helpful to you, as it covers building a list from scratch, adding items to the end of the list (appending), inserting items at an arbitrary point in the list, deleting individual items, and clearing out the whole list.
References
Deleting from a Linked List, Accessed 2014-04-22, <https://www.cs.bu.edu/teaching/c/linked-list/delete/>
Singly linked list - insert, remove, add, count source code, Accessed 2014-04-22, <http://www.cprogramming.com/snippets/source-code/singly-linked-list-insert-remove-add-count>
You have the following 1->2->3->4->5 and you want to remove the element 3. The final result will be 1->2->4->5.
To do this you just need to do the following steps:
1- If the element is in the middle of the list:
Traverse the table, for each element you save previous element and the element itself.
When the element equals the one you want to delete you have cur_el = 3 and prev_el = 2. (cur_el and prev_el are pointers to the elements 3 and 2)
Now just make prev_el->next = cur_el->next (don't forget to keep a pointer to the prev_el.
Finally just free the cur_el.
2- If the element is the first of the list (let's say you want to delete 1):
- Set the first list element as cur_el->next (here cur_el points to 1, the first element in the list)
free the cur_el
3- If the element is in the end of the list (in this case 5):
- go to the last element, get the penultimate element (let's call the pointer to this one prev_el)
set prev_el->next = null
free cur_el
Also, notice that removing an element from the list has a complexity of O(n), where n is the number of elements of the list.
If you just insert and remove from the begin or from the end you can reach a O(1).
In the question, the memory structure is referred to as a 'table'. Perhaps it would be better to call it a 'linked-list'.
int object_destroy(
object **head, /* The head of the linked-list is required in order to maintain proper list nodes linkage. */
object *obj
)
{
int rCode=0;
/* Unlink the node to be destroyed. */
if(*head == obj) /* Is the obj to destroy the head list node? */
*head = obj->next;
else
{
object *temp = *head;
/* Find the parent list node (to the one that will be destroyed). */
while(temp)
{
if(temp->next == obj)
break;
temp=temp->next;
}
/* Not found? */
if(NULL == temp)
{
rCode=ENOENT;
fprintf(stderr, "obj node not found in list\n");
goto CLEANUP;
}
/* Unlink the node, and patch the list so that remaining nodes are not lost. */
temp->next = temp->next->next;
}
/* Free the node to be destroyed. */
if(obj->name)
free(obj->name);
free(obj);
CLEANUP:
return(rCode);
}
Can somebody please explain what this code with pointers does:
while(terminate== 0)
{
s->value=s->next->value;
if ((s->next->next)==NULL)
{
free(s->next);
s->next=NULL;
terminate= 1;
}
s=s->next;
}
where s is passed as a parameter as : set_el* s and having this structure below:
typedef struct set_el
{
int value;
struct set_el* next;
} set_el;
In case of NULL input it will cause a segmentation fault since s->value is illegal.
On a list of size 1 it will similarly fail because s->next->value is illegal.
On a list with a loop (for instance a>b>a...) it will loop endlessly because s->next->next will never be NULL
Finally on a linked list of size 2 or above it will traverse the list coping the value of the next node to the current node and delete the last node.
Effectively it will 'remove' the first node in the list in a very roundabout way. (We free up the last node memory but we copy the values up the list. The new list is 1 node shorter and without the value in the first node).
I've frequently used a linear linked list construct in C
typedef struct _node {
...node guts...
struct _node *next
} node;
And the enumeration idiom
for (node *each = headNode; each != NULL; each = each->next)
I'm in a situation right now, where a circular list is attractive to me (e.g. the next of the last node is set to the headNode). Naively, I thought I'd using something similar to the for expression there, and the more I've stared at it, I think I've convinced myself you can't do something like that with a circular linked list.
It seems that no matter what kind of expression I come up with for the end conditional, I'll have the basic problem that I want said conditional to evaluate true the first time and false the second time the same node is encountered. I could do something with a loop side effect:
for (BOOL traversed = FALSE, node *each = headNode;
traversed && each != headNode;
traversed = TRUE, each = each->next)
But that definitely loses the elegance/simplicity of the null terminated list approach. Is there some trick of logic that's eluding me this late in the day?
Obviously I can use a while() construct, and maybe that's the only way to do it.
Assuming the following:
An empty list means NULL for the starting point.
The last node will be the one who's next pointer references your starting point, including a single-node list who's next pointer self-references.
NO next pointers are NULL.
Then the following will do what you want using a tertiary expression as the incremental step.
// node* start comes from "somewhere'
for (node *p=start; p; p = (p->next==start ? NULL : p->next))
{
// do something with p
}
Note: p will be NULL when this exits, one way or another; start will remain unchanged, and a NULL start is acceptable, as is a single-self-referencing node.
That said, I'd do this with a while-loop, but since you specifically asked for a for-loop you gets that =P.
As you've already pointed out, any "current" pointer will simply cycle through the whole list, being no different on its second time around than the first.
Therefore you must use some other piece of information. As the simplest/smallest additional variable, a boolean, is too complex or inelegant by your admission, it can be inferred that this can't be done.
...unless you're already making use of some additional data, say a "prev" pointer that's initially null (in which case something very similar to your traversed example can be used).
For the record, I'd use a do...while:
struct _node *node = head;
do {
...
node = node->next;
} while (node != head);
I suggest not just to loop a chain. It is not beautiful itself. How do you check you don't loop at the second element of the chain and so on?
If we have a notion of a head then we should hold a pointer to a head in each node or have it static. Also, instead of looping to the head, we should have special flag.
p = (pointer to some node)
pfirst = p
while true:
do whatever with node (p)...
p = p->next
if (p==pfirst) break
Note that this works for a one element list.
The following re-arranged loop doesn't look too terrible:
for (node * n = head; ; )
{
// process n
if ((n = n->next) == head) { break; }
}
By the way, this only works for non-empty lists. Whatever your notion of emptiness is should be added as an initial check — unless you avoid that problem by having dummy head node (so that the empty list contains one node n with n == head == n.next, and in that case, you don't actually want to print the dummy at all and can use a genuine for loop (just put the above condition back into the loop statement)!
If I have a linked list:
first node -----> second node ------> third node ---> ?
Can I show the third node value ( for example ) without use a classic list-linear-searching algorithm?
My attempt of getting the n'th node:
struct node* indexof( struct node* head, int i )
{
int offset = (int)((char*)head->next - (char*)head);
return ((struct node*)((char*)head + offset * i));
}
That depends on your exact linked list implementation, but in general, no. You will have to traverse the list in order to access the nth element.
This is a characteristic of linked lists, in the sense that the normal tricks you could use for computing an offset into an array or other sequence-like structure will not work, as your individual list elements are not guaranteed to be laid out in memory in any sensible way, so you are forced to follow the next pointers in-order to retrieve the third element.
You could consider other data structures that provide constant-time indexed access into your linked list.
Sounds like you've picked the wrong data structure. If you want to go straight to nth then you should use an array.
Failing that, what's so bad about going through in linear fashion? Would have to be called a lot on a very long linked list to be causing performance problem.
One of the purposes of a linked list is to be able to easily add and delete nodes with little cost.
You can renounce that capability and use an array of payload pointers, but then it is no longer a linked list (what would the purpose be of having a pointer to the next node when the same node can be obtained trivially by arithmetic increment?).
E.g. instead of
struct
{
struct node *next;
void *payload;
...
} node;
node *root = NULL;
and allocate space for no nodes, you can have
typedef struct
{
void *payload;
...
} node;
node *vector = NULL;
size_t vectorsize = 0;
and allocate space for as many nodes as initially required, then using realloc to extend the list when needed, and memmove to remove nodes by shifting back the nodes beyond the deleted one. This incurs a clear performance loss when adding or removing nodes. On the other hand, the n-th node is just vector[n].
I repeat, this is no longer a linked list: it may be that whatever you're needing this for, it can be better accomplished with an array of pointers instead than a linked list.
Which reminds me, you'd do well to explain why you need the direct-addressing ability ("State the problem, don't ask how to implement the solution"): it may also well be that what you need is neither an array nor a linked list, but, who knows?, maybe a ring buffer, a stack, a hill, or a binary tree.
In some implementations you can even deploy two bonded structures, e.g. you might use a (doubly?) linked list in a first phase with lots of insertions and deletions especially of recently inserted data; then you build, and switch to, a pointer array for a second phase where you need direct addressing driven by the node number (use the array as "cache" of list node addresses):
for (listsize = 0, scan = root; scan; scan = scan->next)
listsize++;
if (NULL == (vector = (node *)malloc(listsize * sizeof(node))))
{
// out of memory
return EXIT_FAILURE;
}
for (listsize = 0, scan = root; scan; scan = scan->next)
vector[listsize++] = scan;
// Now vector[i]->payload is the payload of the i-th node