Came across Linked Stacks and Queues in a book(and it is not stack/queue implementation using linked list).
it says that stack/queue can be represented sequentially if we had only one stack/queue.However, when several stacks/queues coexisted ,then there is no efficient way to represent them sequentially.
Below is the code given
#define MAX_STACKS 10 //maximum number of stacks;
typedef struct {
int key;
//other fields.
}element;
typedef struct stack *stackpointer;
typedef struct {
element data;
stackpointer link;
}stack;
stackpointer top[MAX_STACKS];
void push(int i ,element item) {
stackpointer temp;
malloc(temp,sizeof(*temp));
temp->data = item;
temp->link = top[i];
top[i] = temp;
}
Am newbie to data structures. Can I get the brief explantion of above concept i.e Linked Stacks/Queues.
So I checked out your book and I kind of understand what your problem is.
Such a representation proved efficient if we had only one stack or one queue. However, when several stacks and queues co−exist, there was noefficient way to represent them sequentially
So, by sequential, you must understand that it means using arrays to represent stacks and not a linked list. Now just assume that you have a matrix comprising of 10 arrays to represent each of size 100, and you push some data into each. Say you push only a few elements in each stack, what happens is that you end up wasting a lot of data as there are a 1000 elements in the matrix. This problem was there while using a single array but it becomes more pronounced when you have multiple arrays for multiple stacks.
Now as you might have understood, using the linked list representation of a stack uses as much memory as needed, with only a slight overhead of keeping track of the next element, in this case stackpointer link.
stackpointer top[MAX_STACKS]
So what we have done here is create an array of type stackpointer to keep track of the top position of each individual stack. So now whenever the user wishes to enter an element, they must pass the index(int i) as well as the data (element item).
void push(int i ,element item)
{
stackpointer temp;
malloc(temp,sizeof(*temp));
temp->data = item;
temp->link = top[i];
top[i] = temp;
}
So what we do is create a temp variable to store our data, which will now become the top of our stack but before doing so we must point it to the previous top of stack, (that is done in line 5) and in line 6, we just point the top[i] to temp.
However, you might want to correct your code with this
stackpointer temp = (stackpointer)malloc(sizeof(element));
If you have doubts, on malloc, just refer to this.
If you have a doubt, let me know and I will clarify anything you need.
Related
I have a Struct Data, this will be a Linked List of Messages. For every new message, I need to append at the last in linked List. I have a Counter where I know how many messages are present.
Instead of parsing till the end of the linked List. Is there any better way to get to the specific position in Linked List??
struct Data {
char *message;
struct Data *next;
}data;
int total_message;
Right now I am parsing like below:
struct Data *traverse;
while(traverse->next != NULL)
traverse = traverse->next;
I tried below as well, I am not sure why this wrong logically it seems right to me.
data[total_messages - 1].next = new_data;
Is there any better way other than storing pointer to Last Message?
Consider maintaining a pointer to the tail of the linked list.
data * head = NULL;
data * tail = NULL;
void Append(data * entry) {
if (!head) {
head = entry;
}
if (tail) {
tail->next = entry;
}
tail = entry;
}
Why traversing (as in the question) is bad?
If we maintain only the head and the number of messages say n, then for each append we have to traverse the n linked nodes starting from head -- that's O(n) operation -- slightly inefficient. If adding to the tail of the list is a frequent operation -- as it seems in your case -- then maintaining the tail pointer is efficient. Space wise, maintaining a counter is same as maintaining a pointer.
Why the following is bad?
data[total_messages - 1].next = new_data;
That's an array notation. Arrays are contiguous block of memory. In linked list, the nodes could be anywhere in memory, they cannot be accessed in array notation like that.
The [] syntax works for arrays because arrays arrange their data in a line, in a predictable way. Linked lists do not. You can only find out where the ith element is by following the next pointers.
data[i] refers to the data i places after the memory address data, which is unlikely to be at the location of a Data struct. Writing data to that position will generally just disrupt a random section of code somewhere else in the program.
A fast and relatively simple solution is to push each new element onto the front of the list while parsing, and then reverse the list in place once you have pushed all the elements.
I'm studying linked lists from this lesson.
The writer (and all other coders on every single tutorial) goes through creating node type pointer variables, then allocates memory to them using typecasting and malloc. It seems kinda unnecessary to me (Offourse I know I'm missing something), why can't we implement the same using this?
struct node
{
int data;
struct node *next;
};
int main()
{
struct node head;
struct node second;
struct node third;
head.data = 1;
head.next = &second;
second.data = 2;
second.next = &third;
third.data = 3;
third.next = NULL;
getchar();
return 0;
}
I've created nodes and the next pointers points towards the addresses of the next nodes...
Let's say you create a variable of type node called my_node:
struct node my_node;
You can access its members as my_node.data and my_node.next because it is not a pointer. Your code, however, will only be able to create 3 nodes. Let's say you have a loop that asks the user for a number and stores that number in the linked list, stopping only when the user types in 0. You don't know when the user will type in 0, so you have to have a way of creating variables while the program is running. "Creating a variable" at runtime is called dynamic memory allocation and is done by calling malloc, which always returns a pointer. Don't forget to free the dynamically allocated data after it is no longer needed, to do so call the free function with the pointer returned by malloc. The tutorial you mentioned is just explaining the fundamental concepts of linked lists, in an actual program you're not going to limit yourself to a fixed number of nodes but will instead make the linked list resizable depending on information you only have at runtime (unless a fixed-sized linked list is all you need).
Edit:
"Creating a variable at runtime" was just a highly simplified way of explaining the need for pointers. When you call malloc, it allocates memory on the heap and gives you an address, which you must store in a pointer.
int var = 5;
int * ptr = &var;
In this case, ptr is a variable (it was declared in all its glory) that holds the address of another variable, and so it is called a pointer. Now consider an excerpt from the tutorial you mentioned:
struct node* head = NULL;
head = (struct node*)malloc(sizeof(struct node));
In this case, the variable head will point to data allocated on the heap at runtime.
If you keep allocating nodes on the heap and assigning the returned address to the next member of the last node in the linked list, you will be able to iterate over the linked list simply by writing pointer_to_node = pointer_to_node->next. Example:
struct node * my_node = head; // my_node points to the first node in the linked list
while (true)
{
printf("%d\n", my_node->data); // print the data of the node we're iterating over
my_node = my_node->next; // advance the my_node pointer to the next node
if (my_node->next == NULL) // let's assume that the 'next' member of the last node is always set to NULL
{
printf("%d\n", my_node->data);
break;
}
}
You can, of course, insert an element into any position of the linked list, not just at the end as I mentioned above. Note though that the only node you ever have a name for is head, all the others are accessed through pointers because you can't possibly name all nodes your program will ever have a hold of.
When you declare 'struct node xyz;' in a function, it exists only so long as that function exists. If you add it to a linked list and then exit the function, that object no longer exists, but the linked list still has a reference to it. On the other hand, if you allocate it from the heap and add it to the linked list, it will still exist until it is removed from the linked list and deleted.
This mechanism allows an arbitrary number of nodes to be created at various times throughout your program and inserted into the linked list. The method you show above only allows a fixed number of specific items to be placed in the list for a short duration. You can do that, but it serves little purpose, since you could have just accessed the items directly outside the list.
Of course you can do like that. but how far ? how many nodes are you going to create ? We use linkedlists when we don't know how many entries we need when we create the list. So how can you create nodes ? How much ?
That's why we use malloc() (or new nodes).
But what if you had a file containing an unknown number of entries, and you needed to iterate over them, adding each one to the linked list? Think about how you might do that without malloc.
You would have a loop, and in each iteration you need to create a completely new "instance" of a node, different to all the other nodes. If you just had a bunch of locals, each loop iteration they would still be the same locals.
Your code and approach is correct as long as you know the number of nodes that you need in advance. In many cases, though, the number of nodes depends on user input and is not known in advance.
You definitely have to decide between C and C++, because typecasting and malloc belong in C only. Your C++ linked list code won't be doing typecasting nor using malloc precisely because it's not C code, but C++ code.
Say you are writing an application such as a text editor. The writer of the application has no idea how big a file a user in the future may want to edit.
Making the editor always use a large amount of memory is not helpful in multi-tasking environments, especially one with a large number of users.
With malloc() an editing application can take additional amounts of memory from the heap as required, with different processes using different amounts of memory, without large amounts of memory being wasted.
You can, and you can exploit this technique to create cute code like this, to use the stack as a malloc in a way:
The code below should be safe enough assuming there are no tail optimizations enabled.
#include <stdio.h>
typedef struct node_t {
struct node_t *next;
int cur;
int n;
} node_t;
void factorial(node_t *state, void (*then)(node_t *))
{
node_t tmp;
if (state->n <= 1) {
then(state);
} else {
tmp.next = state;
tmp.cur = state->n * state->cur;
tmp.n = state->n - 1;
printf("down: %x %d %d.\n", tmp);
factorial(&tmp, then);
printf("up: %x %d %d.\n", tmp);
}
}
void andThen(node_t *result)
{
while (result != (node_t *)0) {
printf("printing: %x %d %d.\n", *result);
result = result->next;
}
}
int main(int argc, char **argv)
{
node_t initial_state;
node_t *result_state;
initial_state.next = (node_t *)0;
initial_state.n = 6; // factorial of
initial_state.cur = 1; // identity for factorial
factorial(&initial_state, andThen);
}
result:
$ ./fact
down: 28ff34 6 5.
down: 28ff04 30 4.
down: 28fed4 120 3.
down: 28fea4 360 2.
down: 28fe74 720 1.
printing: 28fe74 720 1.
printing: 28fea4 360 2.
printing: 28fed4 120 3.
printing: 28ff04 30 4.
printing: 28ff34 6 5.
printing: 0 1 6.
up: 28fe74 720 1.
up: 28fea4 360 2.
up: 28fed4 120 3.
up: 28ff04 30 4.
up: 28ff34 6 5.
factorial works differently than usual because we can't return the result to caller because the caller will invalidate it with any single stack operation. a single function call will destroy the result, so instead, we must pass it to another function that will have its own frame on top of the current result, which will not invalidate the arbitrary number of stack frames it's sitting on top of that hold our nodes.
I imagine there are many ways for this to break other than tail call optimizations, but it's really elegant when it doesn't, because the links are guaranteed to be fairly cache local, since they are fairly close to each other, and there is no malloc/free needed for arbitrary sized consecutive allocations, since everything is cleaned as soon as returns happen.
Lets think you are making an Application like CHROME web browser, then you wanna create link between tabs created by user at run time which can only possible if you use Dynamic Memory Allocation.
That's why we use new, malloc() etc to apply dynamic memory allocation.
☺:).
I have a singly linked list which can have 10000<< nodes at any given time.
Now in the interface I need to print these in order and a user can acces a single node and perform operations on that node. Obviously if the user chooses a very high number on the node count it will have to go over thousands of node before being able to acces the desired node.
My current fix "translates" the linked list to an array, since my code is multithreaded my linked list can grow at any given time. But by code design never shrink.
Here is code I use to translate linked list to array.
unsigned int i=0;
unsigned int LL_arr_bufsize=128;
my_ll **LL_arr;
my_ll *temp;
LL_arr = malloc(LL_arr_bufsize * sizeof(my_ll *));
// err check mem alooc
temp = l_list->next;
while (temp != NULL) {
LL_arr[i] = temp;
temp = temp->next;
if (++i == LL_arr_bufsize) {
LL_arr_bufsize = LL_arr_bufsize * 2;
LL_arr = realloc(LL_arr, LL_arr_bufsize * sizeof(my_ll *));
// err check mem alloc
}
}
What am I basically wondering if there is a better way to acces any given node without incuring the overhead of traversing the entire list before a given node can be accessed...
I will probably get down voted because I literally just thought of this idea and it might have some flaws. Here it goes.
What if you do a two dimensional node stack. Here me out.
NodeList - holds an array of 10 nodes and it's own index. ( you can experiment with bigger values)
What happens is that NodeList is a regular link list that you can de-queue and queue again. But you can get still some of that constant time look-upness that you are looking for. This is done with a clever search function that goes goes through the link list normally however, once it goes to the location of where your particular node is being held in the list you get that constant time look up from the array it stores.
I can probably clarify more of this concept if you want but I think you can get a good picture of what I'm going for with the description.
I've implemented a stack with pointers, that works like it's suppose too. Now, I need it push to the stack, without it pushing a duplicate. For example, if I push '2' into the stack, pushing another '2' will still result with only one '2' in the stack because it already exists.
Below is how I went about trying to create the new push function. I know that I'm suppose to traverse the stack and check it for the element I'm adding, but I guess I'm doing that wrong? Can anyone help me out?
typedef struct Node {
void *content;
struct Node *next;
} Node;
typedef struct Stack {
Node *head;
int count;
} Stack;
void push(Stack *stack, void *newElem) {
Node *newNode = (Node*) malloc(sizeof(Node));
if (stack->count > 0) {
int i;
for (i = 0, newNode = stack->head; i < stack->count; i++, newNode =
newNode->next) {
if (newNode->content == newElem) return;
}
} else {
newNode->next = stack->head;
newNode->content = newElem;
stack->head = newNode;
stack->count++;
}
}
if (newNode->content == newElem)
You are comparing two pointers. I guess you want to check whether their contents are equal:
#include <string.h>
if (memcmp(newNode->content, newElem, size) == 0)
The value size may be indicated by the caller. In your case, it should be sizeof(int).
Moreover, once you have traversed the stack, you don't add the element to your data structure.
The problem is that if your stack is non-empty, and you don't find the element already in the stack, you don't do anything. You need to get rid of the else keyword and make that code unconditional. Then, you allocate space for the new Node before you know if you need it or not, and, even worse, overwrite the newly allocated pointer with your iteration over the stack to see if you need to push it or not. So move the malloc down after the } ending the if
You already have a working
void push(Stack *stack, void *newElem);
right?
So, why not write a new function
int push_unique(Stack *stack, void *newElem) {
if (find_value(stack, newElem) != NULL) {
return 1; // indicate a collision
}
push(stack, newElem); // re-use old function
return 0; // indicate success
}
Now you've reduced the problem to writing
Node *find_value(Stack *stack, void *value);
... can you do that?
I'm not sure you realized it, but your proposed implementation is performing a linear search over a linked list. If you're pushing 2,000 elements on a stack with an average of 2 duplicates of each element value, that's 2,000 searches of a linked list averaging between 500-750 links(it depends on when, IE:what order, the duplicates are presented to the search function in. This requires 1 million+ compares. Not pretty.
A MUCH more efficient duplicate detection in find_value() above could use a hash table, with search time O(1), or a tree, with search time O(log N). The former if you know how many values you're potentially pushing onto the stack, and the latter if the number is unknown, like when receiving data from a socket in real-time. (if the former you could implement your stack in an array instead of a much slower, and more verbose linked-list)
In either case, to properly maintain the hashtable, your pop() function would need to be paired with a hashtable hashpop() function, which would remove the matching value from the hashtable.
With a Hashtable, your stack could just point to the element's value sitting in it's hash location - returned from find_value(). With a self-balancing tree however, the location of the node, and thus the element value, would be changing all the time, so you'd need to store the element's value in the stack, and the tree. Unless you're writing in a very tight memory environment, the performance the 2nd data structure would afford would be well worth the modest cost in memory.
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