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.
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'm trying to create a program that reads a file that is filled with words in the dictionary, then stores every word in the hash table, I already have a hash function, for example the hash function returns an index 123 how will I be able to determine if that index right there has no value yet, else if the certain index has value should I just make the word the new head of the list or should I add it to the end of the list? Should I initialize the whole array first to something like "NULL" because if a variable wasn't initialized it contains garbage value, does that work the same with arrays from a struct..
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// Number of buckets in hash table
// N = 2 ^ 13
const unsigned int N = 8192;
// Hash table
node *table[N];
This is part of my code LENGTH here is defined above with the value of 45..
how will I be able to determine if that index right there has no value yet
The "slots" in your table are linked lists. The table stores pointers to the head nodes of these linked lists. If that pointer is NULL, the list is empty, but you don't need to make it a special case: When you look up a word, just walk the list while the pointer to the next node is not null. If the pointer to the head node is null, your walk is stopped short early, that's all.
should I just make the word the new head of the list or should I add it to the end of the list?
It shouldn't really matter. The individual lists at the nodes are supposed to be short. The idea of the hash table is to turn a linear search on all W words into a faster linear search on W/N words on average. If you see that your table has only a few long lists, your hash function isn't good.
You must walk the list once to ensure that you don't insert duplicates anyway, so you can insert at the end. Or you could try to keep each linked list alphabetically sorted. Pick one method and stick with it.
Should I initialize the whole array first to something like "NULL" because if a variable wasn't initialized it contains garbage value, does that work the same with arrays from a struct.
Yes, please initialize your array of head node pointers to NULL, so that the hash table is in a defined state. (If your array is at file scope or static, the table should be initialized to null pointers already, but it doesn't hurt to make the initialization explicit.)
So I have the following structure:
typedef struct listElement
{
element value;
struct listElement;
} listElement, *List;
element is not a known type, meaning I don't know exactly what data type I'm dealing with, wether they're integers or or floats or strings.
The goal is to make a function that eletes the listElements that are redundant more than twice (meaning a value can only appear 0 times, once or twice, not more)
I've already made a function that uses bruteforce, with a nested loop, but that's a cluster**** as I'm dealing with a large number of elements in my list. (Going through every element and comparing it to the rest of the elements in the list)
I was wondering if there was a better solution that uses less isntructions and has a lower complexity.
You can use a hash table and map elements to their count.
if hashTable[element] (count for this particular element) returns 2, then delete the current element.
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.
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;