In implementing a single linked list in C, I think there are three ways :
HEADER IS A POINTER ITSELF.IT POINTS TO THE FIRST NODE OF THE LINKED LIST.
1.Declare the header globally and use function void insert(int) to insert.This should work as header is global.
2.Declare header inside main and use function node*insert(node*) to insert.This should work because of the return involved.
3.Declare header inside main and use function void insert(node**) to insert.
Sometimes the second way works even without the return involved. Why?
Which is the better way?
If the functions involved are recursive as in tree which method is appropriate?
You should encapsulate your data structure in a single object (the head node or a struct that contains it), and then you can have your functions work on that object. This means that you can have more than one linked list in your program (that won't work with a global head node) and you can also pass it around to different functions that want to use it (there's no point having a data structure without being able to use it).
If you have your single object (head node) stored in your program then the insert and delete functions don't need to return anything, as you already have a pointer to the object that represents the linked list.
If the functions involved are recursive as in tree which method is appropriate?
The functions should not be recursive "as in tree". The depth of a tree is O(logn), which means recursion is reasonable in many situations; The size of a linked list is O(n), which means recursion can easily overflow the stack.
Related
Is it best to keep the head (double pointer) of a linked list inside or outside the structure for the linked list itself?
Having a struct to contain the attributes of the linked list allows you to have multiple instances of a linked list at once.
That said, if the head is the only attribute of the linked list —i.e. if you don't maintain a tail or a count, and if you'd don't support per-list custom allocators and deallocators— then there's no point in using a struct. Well, using a struct would make it easier to add those features if you ever decide you need them.
You will first create an interface for handling string items.
Basically, you will need to do the following:
Create an interface named item.h Define a type Item represents a char
* (i.e., a c-string) Implement a less function that compares between two strings and return which
one should precede. Then, you will add to the linked list interface
the following functions: linkedlistScanInit: The header of the
function will be linkedlistScaninit(pLinkedList list). The function
takes a linkedlist as input, reads from the command line a set of
strings, and store them inside the linkedlist. You can call the
function linkedlistAddNode to add a node to the end of the linked
list. linkedlistShow: The header of the function will be
linkedlistShow(pLinkedList list). The function takes a linkedlist as
input, loops through the linkedlist and show what inside it
Finally, you will create a main, your main will be as follow:
}
You will use the code in linkedListSt.h and linkedListSt.c
sorry its messy its from a pdf and I didn't seem to be able to adjust it without messing it up even more.
So am being asked to basically sort strings in selection sort method on a linked list. my question here isn't anything code specific but what does "less function to compare two strings" mean. does it mean it only needs the declaration?. would that return a string pointer or a string pointer pointer?. Also, I am having trouble understanding the meaning of linkedlistScanInit?
am not entirely sure what the question is here. its not asking me to sort the actual list or at least thats my poor understanding of it.
I'm guessing they mean a function which compares which of two strings is 'lesser' than the other, alphabetically.
The function declaration could look something like this:
int lessThan(char *a, char *b);
which returns 1 if a is lesser than b, and otherwise 0. I'll leave the implementation up to you.
Good luck
I am reading Mastering Algorithms with C by Kyle Loudon, and currently I am struggling with Loudon's implementation of Singly-Linked List in Chapter 5.
Here are the links to the source code. I apologize for not posting them here as they are a bit long.
list.h
list.c
My question is related to the destroy in list.c as it is mentioned in line 11 under
void list_init(List* list, void (*destroy)(void* data))
as list->destroy = destroy
and then again in line 24 as
list->destroy(data).
All I know is that this destroy is different from the function list_destroy but I have no idea what it is. Is it a function or is it just a pointer? What purpose does it serve in the list_init() function for initializing a linked list?
I really appreciate your time and help! The source code is linked above.
It is a function pointer. When you create an instance of this list, you also have to hand the init_list function a function which it will use to destroy the info.
The purpose of a linked list is to store information, and the linked list structure is there to give some structure to
this data. Hence, each element of the list contains a pointer to some data, and a pointer to the next element in the list. However, you want the list to able to handle multiple kinds of data.
Suppose you want to remove an element of the list, then there are basically two things that have to happen:
The data needs to be destroyed
The linked list structure must be restored. Meaning that the predecessor of the element you removed must point to
the next element in the list.
Since you do not know beforehand what kind of data the data pointer in the list will contain, for step 1 a function pointer is provided to handle the destroying of that data.
A linked list is a data structure made up of nodes, each of which contains or links to one piece of data.
The destroy function destroys just one node out of the list.
The list_destroy function destroys an entire list.
In the given implementation, the node actually contains a pointer to its destroy function, and accesses it by dereferencing that pointer. As it happens (so far), all nodes point to the same destroy function. But with more complex data structures this pattern allows multiple types of nodes to be in the data structure. And the equivalent of the list_destroy function will correctly destroy each node type correctly since the node knows how it should be destroyed.
I have recently started working with linked lists. To push an element into linked list in the insert(...) function, I saw we always check if(head == NULL) but it occurs only once.
I want to know if there is any way so that we can avoid the unnecessary check always. Please suggest something that would be relevant to most of the linked list operations. One solution I figured out is that writing a new function "add_first_element(....)" so that explicitly we add the first element and then other elements are added in a generic way.
I am looking for a better solution.
A common way is to use a sentinel node. That is, a node that contains no useful data, but merely serves as the placeholder for the one before the first node. This way you don't need to check for null.
For double-linked list, you will need two sentinel nodes to avoid null checking.
Quoting a code snippet :
/**
* list_add - add a new entry
* #new: new entry to be added
* #head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
I have seen similar code in several different programs, especially those manipulating data structures. What is the usual intention in adding this extra level of indirection - why can't the code inside __list_add be put inside list_add ?
If you copy code, it will make maintenance harder. In this example, the extra level of indirection hides the parameter next. It will provide a function with just 2 parameters rather than 3.
If the code inside the __list_add() is copied, it needs to be copied to multiple places. If then the list mechanism is changed somewhat, all of these places need to be updated too, or bugs will start to pop-up (i.e. a FIFO and LIFO implementation of a list show different behavior).
There is always a tradeoff; another level of indirection also adds complexity and possibly overhead, as opposed to duplicating lines of code or having lots of parameters in the API.
It's about code reuse, and avoiding duplication.
__list_add() contains code that is useful in more situations than just this one, and can be shared between several different functions.
Sharing code like this has several advantages:
If there's a bug in __list_add() and you fix it, all the functions that use it get the fix.
If __list_add() gets an enhancement (eg. you make it faster) all the functions get faster.
There's only one place to look when you want to see how items are added to lists.
It can.
However, there are probably other public entries that can share the code in __list_add(). eg, there may be a push() or an insert_head() or something like that.
NOTE: If this is C++ then you might want to rethink calling your variables new, as this is a reserved word.
__list_add will be intended as a "private" internal function which might have multiple uses internally. The public facing list_add is there as a convenient wrapper around it.
This wrapper is inline. If you added the body of __List_add, that too would be inlined. The apaprent goal is to just inline the pushing of the extra head->next argument and nothing else.
That function comes from the linux kernel.
It belongs to the generic list implementation:
Take a look: __list_add()
__list_add() is used in many places: e.g. list_add() which adds an element at a list head, list_add_tail() which adds an element at list tail... It can also be used to insert an element at a given position.
It is also common to define an wrapper function for recursive functions so the initial parameters are set correctly.
See binary search on wikipedia for Recursion (computer science)
Could also be to keep binary compatibility. you have an indirection that allows to keep the ABI invariant.
From http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html
When a new version of a library is
binary-incompatible with the old one
the soname needs to change. In C,
there are four basic reasons that a
library would cease to be binary
compatible:
The behavior of a function changes so that it no longer meets its
original specification,
Exported data items change (exception: adding optional items to
the ends of structures is okay, as
long as those structures are only
allocated within the library).
An exported function is removed.
The interface of an exported function changes.