I'm new to data structures and it seems like both data structures have more similarities.
In this answer it says that there is a difference in interface.
Please explain it.
A queue is any data structure that is "FIFO = First-In First-Out." It's a waiting-list. (In Britain, the term is used in ordinary conversation ... you "wait in a queue" not "wait in line.")
A stack is any data structure that is "LIFO = Last-In First-Out." It's a pushdown stack like the stack of dishes in a cafeteria.
Linked lists are a possible implementation of either such structure. It consists of nodes which contain pointers to adjacent nodes in the list.
However, there are many other implementations. "Trees" of various kinds can also be used to implement both queues and stacks. Ordinary arrays can do it, although of course arrays cannot "grow."
Ideally, these days, you simply use an appropriate "container class" in your favorite language and fuhgeddabout how it actually was implemented. "You know that it works, therefore you don't care how." Actual implementation of such things is probably an academic exercise.
List is just a list of things (items, objects whatever). For example a list of courses you are taking in your semester. A list of songs that you are listening. A list of answers of this question on this page. There is no order associate with a list. You can add an item to a list anywhere, you can take an item off the list from anywhere, it doesn't change the definition of a list. Its just a grouping of similar (or not so similar) items.
Now consider a list of people standing in front of ATM machine or a bank teller. This list has to observe a particular order. The first person in the line (list) is the one that will be served first (and will be the first to leave this list). A new person coming in will be standing as a last person in the queue and will be served after everyone in front of him has been served. The people in middle of the list are not supposed to jump the line. This is an example of a Queue. You can also guess what a priority Queue would be (think Airlines with silver and gold members on check-ins).
I hope this explains the difference.
A link list is a list of nodes. Each node contain an address field and that address field holding the address of its next node. The reason for this kind of structure is to traverse through the list from its first node till last node. This type of structure is called singly link list. A link list can also be doubly linked, in that structure a node will have two address field where one field will store the address of its previous node and one address will hold the address of its next node. Most important thing of a link list is that its first node address must be stored in an address variable so that we can traverse through the link list at any time.
But Queue can be a link list or an array of nodes. In a list a node can be insert at any place. But in queue a new node must be inserted at the beginning of the list. A queue is working on basis of FIFO i.e. first in first out basis. Hence when you use the pop command on a queue if it is a link list it must remove the last node of the list and return the value of that last node. Hence a queue can be a list as well but with a principle called FIFO based.
You will get more information online. Read properly and try to understand the difference.
I had the same question as you! This is what I found:
A Queue is essentially just more restrictive than a LinkedList. For example, in a LinkedList you can use the method .add(int index, Object obj), but if you try doing that with a Queue interface, you’ll get an error, since with a Queue you can only add elements at the tail end. Similarly, in a LinkedList you can use .remove(int index) as well as .remove(Object obj), but attempting to do this with a Queue will result in an error, since you can only remove an object from the head. So, in essence, the Queue just has less options when it comes to methods you can use on it. (There might be more to it than that, but that’s what was most pertinent to me.)
There are some similarities between the two. For example, they both have the .poll() method, and the result is the same: removes the head element from the Object.
Here are some links in which you can compare the methods of the two (scroll to the bottom of each page to see them all, and you’ll see immediately that LinkedList has a lot more):
https://www.geeksforgeeks.org/linked-list-in-java/ (LinkedList)
https://www.geeksforgeeks.org/queue-interface-java/ (Queue)
In Java (and probably other languages too), a LinkedList implements the Queue interface. So in essence, a LinkedList is a Queue; it has all features that a Queue does and more. Keep in mind, a Queue is not a LinkedList, as a LinkedList is built and expanded upon a Queue.
See this:
Related
I'm trying to implement a container with the following characteristics:
The container has a fixed size n.
When an item is inserted into the container, if the item is in the data structure it will be moved to the front of it. If not it will be inserted to the front of the data structure, but the last item at the back of the container will be removed to respect the fixed size n.
Building on for 2, it will be required to check whether an item exists in this container in order to know whether to insert or move an item in the container.
The reasoning behind this container, is to keep frequently accessed items in the container. The cost of inserting a new item into the container is large thus it is in my interest to keep it in the container for as long as it is in demand.
Is there a container/data structure that exists that achieves something similar to what I've described? If not can you provide any advice on how to implement it? I'm using C++ but any examples or pseudocode will be equally appreciated.
Edit:
I suppose what I need is a kind of queue with no duplicate items. The queue needs to be searched to see if an item exists within it, and if so moves it to the front of the queue. A fixed size isn't that difficult to adhere to (just check the size before insertion and if it will go over remove the last item in the queue). Basically this post but not allowing any duplicates in the container, and also fast search capabilities to check if an item is within it.
I'm not following the requirements you gave but this seems like it can be implemented as as a double-ended queue (C++ deque or Java Deque). Each time an element is accessed implies a linear search (can't be avoided), then this element is moved to the front (constant time), and the last element removed (also constant time). This should result that the most frequently accessed elements move to the front of the queue over time, decreasing the real-time cost of a linear search.
A double-ended queue can be implemented as a ring-buffer or as a doubly-linked-list. Since you stated a fixed number of elements, the ring buffer seems like the better option.
However, I can't vouch for the implementations of C++ or Java deque.. you may look at the source code to see if its backed as an array or a linked node structure.
Maybe wrap a priority queue with elements having a last-accessed-time attribute?
You may check Splay Tree. If you do some operation on element X, that element move to root.
While attempting to reverse a queue, I found a generally agreed upon way:
You can dequeue through the queue, getting the dequeue value and pushing each one into a stack. Then you can go through that stack, popping each value and enqueueing it into the queue
By agreed upon, I mean most of my Google searches on reversing a queue end up taking me to that solution.
Even though that way is correct and relatively performant in linear time, I believe there's a better way that is simpler and more performant in constant time.
Assuming that a queue is implemented using a doubly-linked list, can't you reverse it in O(1) time by just reversing the head and tail pointers?
if you want to treat a doubly linked list as a queue, then it's only by convention which is the head and which is the tail by which way you want to iterate it. But the point of a queue is it's interface.... so given any arbitrary queue, implemented in an unknown way ( there are MANY things that implement queues, including queues that distribute themselves across many computers ) the question is, how can you you reverse it, and that means you cannot rely on an underlying implementation.
A specific implementation might implement optimizations for certain operations.
No, you cannot just swap the head and tail pointers of a doubly linked list. You also need to swap the next and previous pointers in each node. This will still take O(n) time.
Short Answer : NO
LONG ANSWER/REASON
The queue is an abstract data type. That means there is no physical existence of such a data structure. A queue can be implemented in many ways. The most basic implementation is the one that uses arrays.
struct Queue{
int elements[50];//The actual/physical (array)data structure which houses the data
int max=50;//The maximum no of elements that can be stored in this queue.
int front,rear;//pointers to the front and rear.
};
Now, I am sure you know how to define operations on this kind of a Queue.
void enQ(Queue &Q,int new_element);
int deQ(Queue &Q);
int getFront(Queue Q);
That means if I have to add an element 7 to the queue identified by Q, I need to execute enQ(Q,7). Let us say I have added 10 items like that by calling enQ 10 times. Then I add a number 89 to the queue. Now if I have to get this number 89(assume that all numbers are unique), I will first have to deQ the first 10 items and the call the deQ function again to get 89. I am sure you will agree, that is the principle of a queue.
Now time for some magic. If I knew that 89 is the 11th number I added, I can get it directly by Q.elements[(Q.front+11)%Q.max]. Also if I knew that 89 is the number I just added, I can also get it by using Q.elements[Q.rear].
Wow! Does that mean that the principles of the queue got violated? No. It just means that I am not using a queue anymore. I am actually using an array, but trying to fool myself, by doing it in a sophisticated manner(by putting it in a structure and all that).
If you are using a queue, You can only use the three methods I mentioned above. You are not allowed to meddle with the inner workings of the Queue. You might be thinking that your case is different because you are just wanting to change the front and rear values and not the actual data. But No. In a real queue, you are not even allowed to access the front and rear. All you have access to are the three methods I defined above.
That is why the actual implementation of a queue should be
class Queue{
int elements[50];//The actual/physical (array)data structure which houses the data
int max=50;//The maximum no of elements that can be stored in this queue.
int front,rear;//pointers to the front and rear.
public:
void enQ(int new_element);
int deQ();
int getFront();
};
Now we are upholding the real essence of a Queue. A similar layout should be used if you are implementing a queue using a Doubly-linked-list. The front and rear pointers should be private and inaccessible to the user.
Therefore it is not possible to reverse a QUEUE faster than O(n).
So the bottom line is: If you want to change the queue pointers, by using a doubly-linked list, by all means you can do it. But you cannot call it reversing a queue. Because, then you would not be using a queue. In fact, that would be a completely new data structure called DEQ. If you really want to implement reversing a queue in O(1) time complexity, I suggest you go ahead with your method. But you will have to stop calling it a queue because that is a DEQ(BTW, there is nothing wrong with using a DEQ, by all means, use it). Or if you don't like the sounding of a DEQ, you can define your own data structure called reversible queue.
You can define your data structure like
class ReversibleQueue{
DLL front,rear; //pointers to a DOUBLY-LINKED-LIST
public:
void enQ(int new_element);
int deQ();
int getFront();
void reverse();
};
I am looking for a queue algorithm that fulfills the following properties:
Processes communicate using only a shared dictionary (key-value-store)
Does not use any atomic operations other than load and store (no CAS, for example)
Supports multiple producers
Supports a single consumer
Producers can die at any time and queue must remain operational
The consumer can also die at any time and be restarted later, but there will never be more than one consumer-process running at a time
This is meant as a general question about a suitable algorithm, since I'd like to use it in a couple of different scenarios. But to help visualize the requirements, here is an example use-case:
I have a website with two pages: producer.html and consumer.html
producer.html can be opened in multiple tabs simultaneously
Each producer.html adds events to the queue
One copy of consumer.html is open and consumes these events (to aggregate and stream them to a webserver, for example)
If the multiple producer-tabs are opened by the user rather than the page, these tabs do not have references to each other available, so the usual communication methods (postMessage or calling directly into the other tab's JS code) are out. One of the ways they can still communicate with each other is via LocalStorage as suggested here: Javascript; communication between tabs/windows with same origin. But LocalStorage is not "thread-safe" as detailed here.
Note: There may be other ways to implement cross-tab communication in the browser (Flash, ...), but these are NOT the aim of this question as they won't translate to my other use-cases. This is really just an example use-case for the general queue algorithm that I am trying to find.
A couple more parameters:
The number of producers will never be very large (10s or 100s maybe), so the scaling of the number of reads and writes needed with respect to the number of producers is not really a concern.
I don't know before hand how many producers I might have and there is no immediately obvious way to assign a number or index to them. (Many mutex algorithms (Lamport's Bakery, Eisenberg&McGuire, Szymański's, ...) maintain an array of state for each process, which wouldn't necessarily be a natural approach here, although I do not want to exclude these approaches ex ante, if they can be implemented using the shared dictionary in some way...)
The algorithm should be 100% reliable. So, I'd like to avoid things like the delay in Lamport's first Fast Mutex algorithm (page 2 in the PDF) since I don't have any kind of real-time guarantees.
It would be very helpful if the queue was FIFO, but it's not strictly required.
The algorithm should not be encumbered by any patents, etc.
Update:
The Two-Lock Concurrent Queue Algorithm by Michael and Scott looks like it could work, but I would need two things to implement it:
A locking mechanism using the shared dictionary that can survive the crash of a lock-holder
A reliable way to allocate a new node (if I move the allocation into the locked section, I could just generate new random keys until I find one that's not in use yet, but there might be a better way?)
Update 2:
It seems, I wasn't being specific enough about the dictionary:
It's really nothing more than a trivial key-value-store. It provides the functions get(key) to read the value of a key, put(key, value) to change the value of a key, and delete(key) to remove a key. In some of my use-cases, I can also iterate over keys, but if possible, I'd like to avoid it for generality. Keys are arbitrary and the producers and consumers can create or calculate them as needed. The dictionary does not provide any facilities for automatically generating unique keys.
Examples are HTML LocalStorage, Google AppEngine's Datastore, a Java Map, a Python dictionary, or even a file-system with only a single directory (where the keys would be the file-names and the values the content of the files).
After quite a bit of further reading and sleeping on things for a night, I came up with one way that should be able to accomplish what I need, but it might not be the most elegant:
The paper Wait-Free Algorithms for Fast, Long-Lived Renaming by Moir and Anderson generalizes Lamport's Fast Mutex Algorithm #2 (page 6 here) into the following building block (Figure 2):
When n processes enter this section of code, at most one of them will stop, at most n-1 will move right and at most n-1 will move down.
In Lamport's algorithm, stopping means the process acquired the lock, whereas moving right or left will simply send the process back to the beginning of this section of code. To release the lock, a process simply sets Y back to false. (Not quite correct, actually... See "Update" below...)
The big problem with this is that if any of the processes ever die while holding the lock (i.e. before releasing it), the block will simply stay locked forever.
Another problem is that every process needs to be assigned a unique process ID p.
The locked-forever problem can be fixed by borrowing an idea from Moir and Anderson, namely to send processes that end up moving right or down into a different building block rather than back to this one, leading to a structure like this (Figure 3 in the paper):
Except that in this case, I won't be using this grid to assign process IDs as M&A did (although I could probably solve the problem of the unique values for p with this). Instead, every box in the grid will correspond to a very simple queue. If a process stops on a box, it acquired the tail-lock for the corresponding queue (e.g. as per the algorithm by Michael and Scott) and proceeds to enqueue a new element to that queue. Upon completion, it sets the Y value of the box back to false to allow other processes to use this queue. This way, if there is high contention or if processes die before releasing locks, new queues will be created dynamically as needed.
The consumer-process doesn't need to worry about locking the heads of the queues when dequeuing elements, since it's the only process to ever do so. So, it simply traverses the tree of boxes to find all queues and trivially helps itself to their contained elements. One thing to note is that while each individual queue will be FIFO, there is no synchronization between the queues, so the combined queue will not necessarily be FIFO.
If we now change the boolean Y to a time-stamp (or null/0 to indicate false), the consumer can also expire locks after some safe timeout to re-activate dead queues.
A note about implementation using the dictionary:
The shared variables X and Y can be entries in the dictionaries with key-names X_123 and Y_123, where 123 is the number of the box.
p can simply be any unique random string and will be stored as the value of key X_123.
The boolean or time-stamp is also simply stored as the value of key Y_123. The producer-processes interpret a missing entry for Y_123 as false or null/0.
The box-numbers 123 need to be calculated from the move-pattern. One way to do this would be to start with 1 in the top-left corner. If the process stops in that box, we're done. If not, the current number (starting with 1) is shifted left by 1 (i.e. multiplied by 2) and, if the process moved down, also incremented by 1. Smaller (and fewer) numbers can be calculated with a different numbering scheme (I still need to work it out), but this one should work.
The queues then consist of one entry with key H_123 that holds the index of the current head of the queue in its value and one entry with key T_123 that holds the index of the tail. Both default to 0 if they don't exist.
To enqueue an item into queue 123, the tail index is read from T_123 (let's say it yields 48) and an entry with key Q_123_48 is put into the dictionary with its value containing the enqueued item. After, T_123 is incremented by 1.
After the item is enqueued, the Y_123 entry is set back to false or null/0 (not deleted!)
To dequeue an item, the head index is read from H_123 (let's say it yields 39) and compared to the tail index T_123. If it is smaller, an item is available at Q_123_39, which is then read and deleted from the dictionary. After, H_123 is incremented by 1.
To traverse the box-tree, the consumer starts with the box in the top left corner. For each box (e.g. 123), if a key Y_123 exists in the dictionary (even if it contains values null/0 or false), the consumer dequeues items from the corresponding queue, and then recursively moves right and down to the adjacent boxes. If no key Y_123 exists, this box hasn't been used by any processes yet and doesn't need to be considered (and neither do the boxes below or to its right).
I haven't actually implemented this yet, but I'll do that next. I just wanted to post this already to see if it could inspire other approaches or if anyone can see anything wrong with this idea.
Update:
I just noticed one complication: It is possible that if two processes are trying to acquire the lock for a queue simultaneously, both will fail and move on to the next block. This will leave that queue locked forever as no-one will be left to set Y back to false or null/0.
This is the reason why the "Long-Lived Renaming" algorithm by M&A as well as Lamport's algorithm #2 use an array of Y-values in which every process has its own entry that it resets also if it moves on to another block. Y is then only considered false if all entries are false.
Since I don't know before-hand how many processes I will have, I could implement this only if the dictionary had some way of enumerating keys (the keys would then be Y_123_456 where 456 is the value of p for each process).
But, with rare contention and the above described timeout-mechanism for reactivating dead queues, the issue might lead to only a little bit of memory inefficiency, rather than a major problem.
Update 2:
A better way to label the boxes would be this pattern:
If we call the total number of moves n (counting the move into the top left box also, i.e. n ≥ 1) and the number of moves to the right r, then the box-number can be calculated using
box = (n × (n - 1))/2 + r
Just use a RDBMS. It's pretty simple in MS SQL, for PostgresSQL you'd have to use the RETURNING keyword and for MySQL you'd probably have to use triggers.
CREATE TABLE Q ([Key] BIGINT IDENTITY(1,1) PRIMARY KEY, [Message] NVARCHAR(4000))
INSERT INTO Q OUTPUT inserted.* VALUE(#message)
DELETE TOP(1) Q WITH (READPAST) OUTPUT deleted.*
If you were really hoping for an algorithmic solution, just use a ring buffer.
const int MAX_Q_SIZE = 20000000;
static string[] Q = new string[MAX_Q_SIZE];
static long ProducerID = 0;
static long ConsumerID = 0;
public static long Produce(string message) {
long key = Interlocked.Increment(ref ProducerID);
int idx = (int)(key % MAX_Q_SIZE);
Q[idx] = message;
return key;
}
public static string Consume() {
long key = Interlocked.Increment(ref ConsumerID);
int idx = (int)(key % MAX_Q_SIZE);
string message = Q[idx];
return message;
}
I heard an interview question:
"Print a singly-linked list backwards,
in constant space and linear time."
My solution was to reverse the linkedlist in place and then print it like that. Is there another solution that is nondestructive?
You've already figured out most of the answer: reverse the linked list in place, and traverse the list back to the beginning to print it. To keep it from being (permanently) destructive, reverse the linked list in place again as you're traversing it back to the beginning and printing it.
Note, however, that this only works if you either only have a single thread of execution, or make the whole traversal a critical section so only one thread does it at a time (i.e., a second thread can never play with the list in the middle of the traversal).
If you reverse it again after printing it will no longer be destructive, since the original order is restored.
You could use a recursive call down the linked list chain with a reference to what you wish to write to. Each node would use the child node's print function while passing the reference before printing itself.
That way each node in the list would pass down, until the last one couldn't and would go straight to the write, then each one back up the chain would write after the last all the way back up to the front.
Edit
This actually doesn't fit the specs because of the linear space on stack. If you had something outside to walk the functions and a method of writing to the front of a string the base logic can still work though.
Okay , this could be an interview question , but it is actually a question behind weis algorithms book. The question clearly states that we cannot use recursion (something the interviewer will hide and reveal later on) as recursion will not use constant space, moslty recursion will become a major point of discusion going forward. Solution is reverse print and reverse back.
Here's an unconventional approach: Change your console to right-to-left reading order and then print the list in normal order. They will appear in backward order. Having to visit the actual data in reverse order doesn't sound like a constraint to the problem.
This needs to be lock free as it has to run in the interrupt handler of an SMP system. I cannot take locks.
I have a contiguous array holding some values. Some of the entries in this array are "free", they are not occupied. I want to make a list of these entries so that I can quickly allocate one. However, I occasionally have to allocate an arbitrary entry.
Therefore, I see the following would be a nice way of doing things:
The contiguous array holds not just values but also left and right pointers, thus making a deque. Only free values have valid left/right pointers. I can quickly get to arbitrary nodes because it is just an index access into the deque.
Now, to the crux of it: Is there a nice lock free deque algorithm that is relatively efficient and can support the removal of an arbitrary node?
The contiguous array holds not just values but also left and right pointers, thus making
a deque.
[snip]
Now, to the crux of it: Is there a nice lock free deque algorithm that is relatively
efficient and can support the removal of an arbitrary node?
A deque with the ability to remove arbitrary elements is really a doubly linked list; the only thing you've given up is the ability to insert arbitrary elements and removing is the hard part - if you can remove, you can certainly add.
A lock-free doubly linked list exists, but it requires garbage collection.
How about this; have a freelist. This represents available nodes. The nodes are actually an array, so you can index into them. When you have to use an arbitrary node, index into the array and then CAS a flag in that element but leave it in the freelist (you have to of course, since it's not at the top of the freelist). When you come in future to pop and you find you pop an element which has already been used, just keep popping till you find one which is free.
In a garbage-collected system, it's possible to have a singly linked list support lock-free logical removal of items, if you don't care about when the memory for the items physically gets freed, and if it's not possible to add an item immediately following an item that's being deleted. Give each item a deleted flag, and have a list-traversal routine that will check as it visits each item whether the following node has been deleted; if it has, use compare and swap to swing the present node's "next" pointer around it. Note that it's possible that the "next" pointer of the node which was being deleted might get changed, but only to skip the node following it. It's possible that swinging a next pointer might cause a node which has just been unlinked from the list to get relinked (e.g. A->B->C->D might, if B and C are removed simultaneously, become A->B->D (swinging B
s pointer) and then A->C->D (swinging A's pointer to the latched value of B's 'next' pointer). If node C was and continues to be flagged as "deleted", however, that shouldn't pose a problem, since the next time the list is iterated, A's pointer will swing to D.
Two caveats: -1- In a non-garbage-collected system, it may be difficult to know when a node can really be freed; freeing a node and then swinging a pointer back to it could cause Undefined Behavior; -2- If a node is added immediately following a deleted node, a pointer may swing so as to disconnect the new node. If nodes will always be added to the end of the queue, one can avoid this latter problem by ending the queue with a dummy node, which cannot be deleted until there's another node following it.