So I'm still trying to wrap my head around linked lists in C. They are.. mind-boggling to me right now because I have yet to fully understand pointers, let alone pointers to pointers, and dynamic memory allocation that linked lists require.
I'm trying to create a two dimensional array with independent height, and width values. At most they would be 30x30. I have a two dimensional array let's call it arr[x][y]. arr[x][y] is filled with values of integers ranging from -2 to 1, how would I transfer this two dimensional array into a linked list? How would I then access values from this linked list on whim? I'm very confused, and any help would be appreciated. I'm looking through tutorials as we speak.
Additionally this is supposed to be a sort of stack linked list where I could call functions such as push(pushes a new value to the top of the linked list), pop(pops a value from the top of the linked list), top(returns the value most recently pushed onto the stack), isEmpty(checks if the stack is empty).
I don't need any full code, but code would be helpful here. I just need an understanding though of Linked Lists, and how to implement these sort of functions.
Additionally here is the assignment that this is related to: Assignment
It's a maze solver, I've already done code for analyzing a ascii picture into integer values for the two dimensional array. And as stated above that is what I need help with.
Hint : from your assignment, the stack is not supposed to fully represent the array, but to represent a path you dynamically build to find a way from the starting position of the maze to the target position of the maze.
Basically you need to create a link list, whose each node is the head of another list contained as a member (which conceptually grows downwards), along with a usual next pointer in the list.
For accessing an element like 2D array such as arr[3][4], you need to walk the first list while keeping a count of yand then move downward counting x Or you could do vice versa.
This is a common data structure assignment which goes by the name "multi stack or multi queue" which if implemented by lists gives what you are looking for.
struct Node
{
int data;
struct Node *next;
struct Node *head; // This head can be null initially as well as for the last node in a direction
};
First of all you need to define the proper structure.The first times it will be easier for you to create a list that terminates when the pointer to the next node is NULL.Afterwards you will discover lists with sentinel, bidirectional lists and things that now may seem too complicated.
For example that's a structure:
typedef struct __node
{
int info;
struct __node* next;
}node;
typedef node* list;
This time let's assume that list and node are the same thing, you will find more precise to separate the concept of list than the concept of node, and for example you may store in the list it's length (avoiding to count everytime all the nodes), but for now let's do it that way.
You initialize the list:
list l=NULL;
So the list contains zero nodes, to test if it's empty you just see if the pointer is NULL.
Add a new element:
if(NULL==l)
{
l=(node*)malloc(sizeof(node));
l->next=NULL;
l->info=0;
}
Now the list contains zero nodes, create a function to add a new node:
void pushBack(list* listPointer, int info)
{
if(NULL==*listPointer)
{
*listPointer=(node*)malloc(sizeof(node));
(*listPointer)->info=info;
}
else
{
node* ptr=l;
while(ptr->next!=NULL)
ptr=ptr->next;
ptr->next=(node*)malloc(sizeof(node));
ptr->info=info;
}
}
You could also gain efficiency adding the elements in front.Or optimize the code by returning the added element, so that you don't have to find the last element everytime.I leave this to you.Now let's call the pushBack function for every element of the array:
for(int i=0; i<N; i++)
{
pushBack(l,arr[i]);
}
That's all, learn your way to implement linked lists.
You're not supposed to convert the whole array into a linked list, you're only supposed to convert the best path into a linked list. You'd do this by brute force, trying directions and backtracking when you ran into dead ends.
Your path, the linked list, would need to look something like this:
struct PathNode
{
int coordX, coordY;
PathNode * next, * prev;
}
If I remember later, I'll draw a picture or something of this structure and add it to the post. comment on this post in a few hours to attract my attention.
The list would always contain a starting point, which would be the first node in the list. As you moved to other positions, one after the other, you'd push them onto the end of the list. This way, you could follow your path from your current position to the beginning of the maze by simply popping elements off of the list, one by one, in order.
This particular linked list is special in that it's two way: it has a pointer to both the next element and the previous one. Lists with only one of the two are called singly linked lists, this one with both is called a doubly linked list. Singly linked lists are one way only, and can only be traversed in one direction.
Think of your linked list as giant pile of strings, each with a starting end and a finishing end. As you walk through the maze, you tie a string at every node you visit and bring an end with you to the next square. If you have to backtrack, you bring the string back with you so it no longer points to the wrong square. Once you find your way to the end of the maze, you will be able to trace your steps by following the string.
Could you just explain what -> means exactly?
-> is an all-in-one pointer dereference and member access operator. Say we have:
PathNode * p = malloc(sizeof(*p));
PathNode q;
We can access p's and q's members in any of the following ways:
(*p).coordX;
q.coordX;
p->coordX;
(&q)->coordX;
Related
So let's say I have a list node like this:
struct node{
data_t data;
struct node* prev;
struct node* next;
};
I usually travelled through the list by using the prev/next addresses stored in the list.
If I'm not mistaken when I have a type_t *cursor and just do cursor++ it points to the next data area of its type;
so I was wondering if I could just remove prev/next pointers from the struct and travel in the list by adding/subtracting to a
struct node *cursor
,to save on allocated memory.
Maybe if i remove the said pointers it is not guaranteed that the nodes will be adjacent to one another in the order they were allocated? Or is there something else in this reasoning that might make errors?
My hope would be that if I malloc ten structs and then take a struct node* cursor on the list head's address and do cursor=cursor+7 I get the 7th node of the list, but maybe I am wrong and doesn't work like that?
if your node are allocated one by one you cannot go to the next/prev by incr/decr a pointer to one of them because you cannot suppose they are adjacent in memory
My hope would be that if I malloc ten structs and then take a struct node* cursor on the list head's address and do cursor=cursor+7 I get the 7th node of the list, but maybe I am wrong and doesn't work like that?
you can do that, the advantage is you do not need the prev/next pointer so you only memorize data saving place, the time to access an element is also immediate rather than to be on O(n), the disadvantage is when you want to add/remove element(s) because you have to move the ones after.
Note having an array you can also access an element with an index rather than to have a pointer to that element.
The function realloc allows to change the size of your dynamic array, both to add or remove elements from its end
"Can I go back and forth in a list just with pointer algebra and remove prev/next pointers?"
"Maybe if I remove the said pointers it is not guaranteed that the nodes will be adjacent to one another in the order they were allocated?"
You can go back and forth if you have an static or dynamically allocated array of struct node. Then it is guaranteed that each element is stored in subsequent order and you can use pointer arithmetic.
Unfortunately, in the most cases when using linked lists, this is not the case, as each node is allocated separately.
"So I was wondering if I could just remove prev/next pointers from the struct and travel in the list by adding/subtracting to a struct node *cursor, to save on allocated memory."
As said above, only when you allocated an array of node. Else if each and every node is allocated separately, then you can't or better said it is undefined behavior by any attempt.
The C standard prohibits incrementing a pointer after one past an aggregate or an scalar object.
Not to mention that of course dereferencing a pointer, which points after an aggregate or scalar object, is also not allowed.
"My hope would be that if I malloc() ten structs and then take a struct node* cursor on the list head's address and do cursor = cursor + 7 I get the 7th node of the list, but maybe I am wrong and doesn't work like that?"
It works only if you malloc() all ten structures by one call to malloc. Then the structures are stored adjacent in memory and pointer arithmetic guaranteed to work.
Also note that you need to use cursor = cursor + 6; to get to the 7th node, not cursor = cursor + 7; as indexing starts at 0, not 1.
I need a way to implement a doubly linked list using only an array and no pointers in C. There's is a mention of this in Thomas Cormen but I can't think of a way to actually implement it.
Instead of using pointers which, in C, are usually numbers that index into the address space, use integer indexes into your array as references to the previous and next members e.g.
struct Element
{
int next;
int prev;
// Any data you want for this element in the list
};
struct Element array[MAX_ELEMENTS];
Then for the element at index i in the array, the next element in the list is
array[array[i].next]
and the previous element is
array[array[i].prev]
Instead of using NULL to mean a null pointer, use -1 to mean a "null" index.
This question already has answers here:
Why do linked lists use pointers instead of storing nodes inside of nodes
(11 answers)
Closed 5 years ago.
I could not grasp the reason we create pointers of nodes instead of node structures when we try to implement linked lists as here:
typedef struct node {
int val;
struct node * next;
} node_t;
and
node_t * head = NULL;
head = malloc(sizeof(node_t));
if (head == NULL) {
return 1;
}
head->val = 1;
head->next = NULL;
here, why do we declare nodes such as head as pointers of structures instead of direct structures>
Having head as a pointer allows for things like empty lists (head == NULL) or a simple way to delete elements at the front of the list, by moving the head pointer to another (e.g. second) element in the list. Having head as a structure, these operations would be impossible or at least much less efficient to implement.
The primary reason is that the C language simply won't allow it - a struct type cannot contain an instance of itself. There are two reasons for this:
The struct type is not complete until the closing }, and you cannot create an instance of an incomplete type;
If a struct type could contain an instance of itself, then the instance would be infinitely large (struct foo contains an instance of struct foo, which contains an instance of struct foo, which contains an instance of struct foo, ad infinitum).
You can, however, create pointers to incomplete types (since the size of the pointer doesn't depend on the size of the pointed-to type). So if you want a struct type to contain a member that refers to another instance of the same type, it must be done through a pointer.
why do we declare nodes such as head as pointers of structures instead of direct structures
Declaring head as a pointer allows us to have an empty list, i.e. when head is NULL
Because that's the whole point: a collection of nodes, that are linked like a chain. You can detach and re-attach nodes with ease and poise, because to do so you need only change pointer values. This would be impossible if your type were more like an array. If you want that, use an array.
Besides which, it is impossible for a type to contain an instance of itself. So a node contains a node, which contains a node, which contains a node, which contains a node, and so forth… how can that work?
As someone else has already said, by using pointers we have a convenient way of indicating an empty list or the end of the list by using a NULL pointer.
We could of course modify our nodes to have a flag indicating that it is "the end of the list" (EOL). However, another important reason it that is give the list the ability to easily grow (up to the amount amount of available memory) or shrink dynamically without having to reallocate memory to hold the entire list and copy it every time that it grows or shrinks. It also makes it easier to insert or remove an item.
It would not be a "linked" list if the nodes are not actually linked to each other. It could still be a list of some sort, but it would not be linked.
Compare to the word "link" or hyperlink on the internet. They are also pointers, because almost no site store actual contents of the linked sites.
I want to create a list in C that the head and tail are NOT pointers, but a nodes by value. can it be done?
I want to use the head and the tail as an empty frame to put the list between. I do know how to create it as pointers and only want to know this because I just realise I don't know how to do this alone.
struct List{Node head, Node tail};
struct Node{struct Node* next, struct Node* prev, void* data};
The main advantage of the list with dummy head and tail (the way you presented here) is that you have no special cases in the list functions (insert, remove, ... etc).
Head and tail pointers make you take care of special cases in each function.
It's not possible to have a linked list1 of non pointer objects and it doesn't make sense at all, because the whole point of the list is that the next and previous members POINT to another instance of the same type, hence they MUST BE pointers.
[1]Single or Double linked list.
I'm currently trying to find the best data structure / algorithm that fits to my case:
I receive single unique random ids (uint32_t), and I create an element associated to each new id.
I need to retrieve elements from the id.
I also need to access the next and the previous element from any element (or even id) in the order of creation. The order of creation mainly depends on the current element, which is always accessible aside, so the new element should be its next.
Here is an example:
(12) <-> (5) <-> (8) <-> (1)
^ ^
'------------------------'
If I suppose the current element to be (8) and a new element (3) is created, it should look like:
(12) <-> (5) <-> (8) <-> (3) <-> (1)
^ ^
'--------------------------------'
An important thing to consider is that insertion, deletion and search happen with almost the same (high) frequency. Not completely sure about how many elements will live at the same time, but I would say max ~1000.
Knowing all of this, I think about using an AVL with ids as the sorted keys, keeping the previous and the next element too.
In C language, something like this:
struct element {
uint32_t id;
/* some other fields */
struct element *prev;
struct element *next;
}
struct node {
struct element *elt;
struct node *left;
struct node *right;
};
static struct element* current;
Another idea may be to use a hash map, but then I would need to find the right hash function. Not completely sure it always beats the AVL in practice for this amount of elements though. It depends on the hash function anyway.
Is the AVL a good idea or should I consider something else for this case?
Thanks !
PS: I'm not a student trying to make you do my homework, I'm just trying to develop a simple window manager (just for fun).
You are looking for some variation of what's called in java a LinkedHashMap
This is basically a combination of a hash-table and a (bi-directional) linked list.
The linked-list has elements in the desired order. Inserting an element in a known location (assuming you have the pointer to the correct location) is done in O(1). Same goes for deletion. The linked list contains all the elements in their desired order.
The second data-structure is the hash-map (or tree map). This data structure maps from a key (your unique id), to a POINTER in the linked list. This way, given an id - you can quickly finds its location on the linked-list, and from there you can easily access next and previous elements.
high level pseudo code for insertion:
insert(x, v, y): //insert key=x value=v, after element with key=y
if x is in hash-table:
abort
p = find(hash-table,y) //p is a pointer
insert_to_list_after(x,v,p) //insert key=x,value=v right after p
add(hash-table,x,p) //add x to the hash-table, and make it point to p.
high level pseudo code for search:
search(x):
if x is not in hash-table:
abort
p = find(hash-table,x)
return p->value;
deletion should be very similar to insertion (and in same time complexity).
Note that it is also fairly easy to find element that is after x:
p = find(hash-table,x)
if (p != NULL && p->next != NULL):
return p->next->value
My suggestion is that you use a combination of two data structures - a list to store the elements in the order they are inserted and a hash map or binary search tree to implement an associative array(map) between the id and list node. You will perform the search using the associative array and will be able to access neighboring elements using the list. Deletion is also relatively easy, but you need to delete from both structures.
Complexity of find/insert/delete will be log(n) if you use binary search tree and expected complexity is constant if you use a hash table.
You should definitely consider the Skip List data structure.
It seems perfect for your case, because it has an expected O(log(n)) insert / search / delete and if you have a pointer to a node, you can find the previous and the next element in O(1) by just moving that pointer.
The conclusion is that if you've just created a node, you have a pointer to it, and you can find the prev/next element in O(1) time.