Why and when should I use stack or queue data structures instead of arrays/lists? Can you please show an example for a state thats it'll be better if you'll use stack or queue?
You've been to a cafeteria, right? and seen a stack of plates? When a clean plate is added to the stack, it is put on top. When a plate is removed, it is removed from the top. So it is called Last-In-First-Out (LIFO). A computer stack is like that, except it holds numbers, and you can make one out of an array or a list, if you like. (If the stack of plates has a spring underneath, they say you "push" one onto the top, and when you remove one you "pop" it off. That's where those words come from.)
In the cafeteria, go in back, where they wash dishes. They have a conveyor-belt where they put plates to be washed in one end, and they come out the other end, in the same order. That's a queue or First-In-First-Out (FIFO). You can also make one of those out of an array or a list if you like.
What are they good for? Well, suppose you have a tree data structure (which is like a real tree made of wood except it is upside down), and you want to write a program to walk completely through it, so as to print out all the leaves.
One way is to do a depth-first walk. You start at the trunk and go to the first branch, and then go to the first branch of that branch, and so on, until you get to a leaf, and print it. But how do you back up to get to the next branch? Well, every time you go down a branch, you "push" some information in your stack, and when you back up you "pop" it back out, and that tells you which branch to take next. That's how you keep track of which branch to do next at each point.
Another way is a breadth-first walk. Starting from the trunk, you number all the branches off the trunk, and put those numbers in the queue. Then you take a number out the other end, go to that branch, and for every branch coming off of it, you again number them (consecutively with the first) and put those in the queue. As you keep doing this you are going to visit first the branches that are 1 branch away from the trunk. Then you are going to visit all the branches that are 2 branches away from the trunk, and so on. Eventually you will get to the leaves and you can print them.
These are two fundamental concepts in programming.
Because they help manage your data in more a particular way than arrays and lists.
Queue is first in, first out (FIFO)
Stack is last in, first out (LIFO)
Arrays and lists are random access. They are very flexible and also easily corruptible. IF you want to manage your data as FIFO or LIFO it's best to use those, already implemented, collections.
Use a queue when you want to get things out in the order that you put them in.
Use a stack when you want to get things out in the reverse order than you put them in.
Use a list when you want to get anything out, regardless of when you put them in (and when you don't want them to automatically be removed).
When you want to enforce a certain usage pattern on your data structure. It means that when you're debugging a problem, you won't have to wonder if someone randomly inserted an element into the middle of your list, messing up some invariants.
Stack
Fundamentally whenever you need to put a reverse gear & get the elements in constant time,use a Stack.
Stack follows LIFO it’s just a way of arranging data.
Appln:
Achieving the undo operation in notepads.
Browser back button uses a Stack.
Queue:
Queues are implemented using a First-In-Fist-Out (FIFO) principle
Appln:
In real life, Call Center phone systems will use Queues, to hold people calling them in an order, until a service representative is free.
CPU scheduling, Disk Scheduling. When multiple processes require CPU at the same time, various CPU scheduling algorithms are used which are implemented using Queue data structure.
In print spooling
Breadth First search in a Graph
Handling of interrupts in real-time systems. The interrupts are handled in the same order as they arrive, First come first served.
Apart from the usage enforcement that others have already mentioned, there is also a performance issue. When you want to remove something from the beginning of an array or a List (ArrayList) it usually takes O(n) time, but for a queue it takes O(1) time. That can make a huge difference if there are a lot of elements.
Arrays/lists and stacks/queues aren't mutually exclusive concepts. In fact, any stack or queue implementations you find are almost certainly using linked lists under the hood.
Array and list structures provide a description of how the data is stored, along with guarantees of the complexity of fundamental operations on the structures.
Stacks and queues give a high level description of how elements are inserted or removed. A queue is First-In-First-Out, while a stack is First-In-Last-Out.
For example, if you are implementing a message queue, you will use a queue. But the queue itself may store each message in a linked list. "Pushing" a message adds it to the front of the linked list; "popping" a message removes it from the end of the linked list.
It's a matter of intent. Stacks and queues are often implemented using arrays and lists, but the addition and deletion of elements is more strictly defined.
A stack or queue is a logical data structure; it would be implemented under the covers with a physical structure (e.g. list, array, tree, etc.)
You are welcome to "roll your own" if you want, or take advantage of an already-implemented abstraction.
The stack and the Queue are more advanced ways to handle a collection that the array itself, which doesn't establish any order in the way the elements behave inside the collection.
The Stack ( LIFO - Last in first out) and a Queue (FIFO - First in First out ) establish and order in which your elements are inserted and removed from a collection.
You can use an Array or a Linked List as the Storage structure to implement the Stack or the Queue pattern. Or even create with those basic structures more complex patterns like Binary Trees or priority queues, which might also bring not only an order in the insertion and removal of elements but also sorting them inside the collection.
There are algorithms that are easier to conceptualize, write and read with stacks rather than arrays. It makes cleaner code with less control logic and iterators since those are presupposed by the data structure itself.
For example, you can avoid a redundant "reverse" call on an array where you've pushed elements that you want to pop in reverse order, if you used a stack.
I think stack and queue both are memory accessing concepts which are used according to application demand. On the other hand, array and lists are two memory accessing techniques and they are used to implement stack(LIFO) and queue(FIFO) concepts.
The question is ambiguous, for you can represent the abstract data type of a stack or queue using an array or linked data structure.
The difference between a linked list implementation of a stack or queue and an array implementation has the same basic tradeoff as any array vs. dynamic data structure.
A linked queue/linked stack has flexible, high speed insertions/deletions with a reasonable implementation, but requires more storage than an array. Insertions/deletions are inexpensive at the ends of an array until you run out of space; an array implementation of a queue or stack will require more work to resize, since you'd need to copy the original into a larger structure (or fail with an overflow error).
Stacks are used in cache based applications, like recently opened/used application will comes up.
Queues are used in deleting/remove the data, like first inserted data needs to be deleted at first.
The use of queue has always been somewhat obscure to me (other than the most obvious one).
Stacks on the other hand are intrinsically linked to nesting which is also an essential part of backtracking.
For example, while checking if in a sentence brackets have been properly closed or not, it is easy to see that
sentence := chars | chars(chars)chars | chars{chars}chars | chars[chars]chars --- suppose cases like (chars) is not valid
chars := char | char char
char := a | b | ... | z | ␢ --- ignored uppercase
So now, when checking a given input is a sentence, if you encounter a (, you must check whether the part from here to ) is a sentence or not. This is nesting. If you ever study about context free languages and the push down automata, you will see in detail how stacks involved in these nested problems.
If you want to see difference between the use of stacks and queues, I recommend that you look up Breadth-First Search and Depth-First Search algorithms and their implementations.
Related
Why do we need stacks when we already have so many data structures that can also handle managing data in reverse directions [linked list & vectors]?
What's so useful/distinctive about stacks that other data structures don't have?
Also, why are only arrays and linked lists compatible with stacks, why arent vectors compatible with stacks?
This sounds like a homework question. I'd argue the final question is based on a flawed premise.
First, stacks are an age-old concept. Every computer I've ever programmed at the assembly code level has used them. So partly they exist for historical reasons.
But it's a useful concept. Stacks have three basic operations:
Push
Peek
Pop
They're an easy, first-in, last-out structure. They're GREAT for certain types of languages. There are programming languages built on the concept of stacks. They're exceedingly easy to write. (The language itself.) And they're kind of fun.
For instance:
8 7 mul
That's legal code in PostScript and a variety of other stack-based languages. The interpreter breaks that into tokens and then it sees an 8 and pushes it onto the stack. It sees the 7 and pushes that. It sees the mul and knows multiple takes two operands, so it pops the 7, pops the 8, multiplies them, and pushes 56. When that line is done, the stack has just a 56 on it (plus whatever was on it earlier than this.
Stacks are also a very useful in other forms of parsing. I use them when parsing certain types of input (like XML). When I reach an "end of object" marker, then I pop the top item on the stack, and the next thing I encounter in my input is working on the new top of stack item.
But stacks are a CONCEPT, not an IMPLEMENTATION. Arrays, linked lists, and vectors are all reasonable ways to implement a stack.
As for the last question -- it's a flawed question. What's the difference between an array and a vector? Well, that might be language-specific. In C++, arrays are fixed-length (and I almost never use them). I would use a vector to implement a stack, with the top of the stack being the last item in the vector.
That's a lighter-weight answer than using linked lists, depending upon how big your stack is going to grow. (Every time you grow a vector beyond whatever is allocated, it can be kind of expensive, so if you don't allocate enough space ahead of time, linked lists might be cheaper.)
After doing some reading + research, here's what I think:
Why do we need stacks when we already have so many data structures that can also handle managing data in reverse directions [linked list & vectors]?
we need stacks because of their feature to store data in reverse, and output the data in LIFO, along with their simplicity. Other data structures store data in sequential order, the order in which the data was originally provided, and stacks go in LIFO [this sequence is needed when working with applications]. Also since stacks are much simpler to use compared to linked lists and vectors, they are the ideal candidate, with their top powers of push, peek, and pop.
Think of it like this: "Don't use a bomb to kill flies when you have a net"
What's so useful/distinctive about stacks that other data structures don't have?
Other data structures are not as simple as stacks since stacks have 3 built-in functions: push, peek and pop. And even though we can store data reversed in vectors and linked lists, it is much more complicated. So think of it as a simple tool to get the job done.
Think of it like this: we use a for-loop even though we have a while loop that does the same job, but a for-loop is short simple and built for that specific purpose, whereas a while loop is a bigger and a bit unnecessary for a task that a for-loop can accomplish
Also, why are only arrays and linked lists compatible with stacks, why aren't vectors compatible with stacks?
With stacks, we use arrays and linked lists and NOT VECTORS because stacks were created using vectors. Hint, hint push, pop, are features that vectors have as well... Also, storing a vector within a stack is like storing a vector within a vector that is wrong and the compiler will throw an exception.
A stack is an ADT (abstract data type), consisting of a mathematical model (a sequence of elements) and some operations performed on that model (push, pop, isEmpty, makenull, and top). In many applications, these are the only operations you would want to do on a list: every time you delete an element, it’s the element that was most recently inserted into the list. An important application of stacks is call stacks, which are used to implement procedure calls. When a procedure A calls a procedure B in your program, a new stack frame for procedure B is pushed onto the call stack.
ADT’s are called interfaces in Java, and are the specs, while data structures are about how these specs are implemented. A stack can be implemented using an array data structure, or a linked list data structure, in such a manner that all the five stack ADT operations can be performed in O(1) time.
So, I wouldn’t call a stack a data structure; I would call it an ADT. Examples of data structures include arrays, sorted arrays, linked lists, doubly linked lists, binary search trees, hash tables, max heap, etc. Each data structure is well suited for a subset of operations that they perform efficiently on. Depending on which subset of operations (ADT) arises in your application or algorithm, you can choose a data structure that performs this subset of operations efficiently.
From Algorithms 4th:
1.3.48 Two stacks with a deque. Implement two stacks with a single deque so that each
operation takes a constant number of deque operations (see Exercise 1.3.33).
What's the meaning of implementing 2 stacks with 1 single deque? Any practical reasons? Why don't I just create 2 stacks directly?
1.3.49 Queue with three stacks. Implement a queue with three stacks so that each
queue operation takes a constant (worst-case) number of stack operations. Warning :
high degree of difficulty.
Related question: How to implement a queue with three stacks?
Also, why do I have to implement a queue with three stacks? Can't I just create a queue directly too?
That first problem looks more like it's designed as an exercise than as anything else. I doubt that there are many cases where you'd want to implement two stacks using a single deque, though I'm happy to be proven wrong. I think the purpose of the question, though, is to get you to think about the "geometry" of deques and stacks. There's a really beautiful solution to the problem that's quite elegant, and if you see how it works it'll give you a much deeper appreciation for how all these types work.
To your second question - in imperative programming languages, there isn't much of a reason to implement a queue with three stacks. However, in functional programming languages like Lisp, typically, stacks are fairly simple to implement, but it's actually quite difficult to get a queue working with a constant number of operations required per operation. In fact, for a while, if I remember correctly, it was believed that this simply wasn't possible. You could implement a queue with two stacks (this is a very common exercise, and it's actually a really good one because the resulting queue is extremely fast), but this usually only gives good amortized performance rather than good worst-case performance, and in functional languages where amortization is either not a thing or much harder to achieve this isn't necessarily a good idea. Getting a queue out of three stacks with constant complexity is a Big Deal, then, as it unlocks the ability to use a number of classical algorithms that rely on queues that otherwise wouldn't be available in a functional context.
But again, in both cases, these are primarily designed as exercises to help you build a better understanding of the fundamentals. Would you actually do either of these things in practice? Probably not - some library designer will likely do it for you. But will doing these exercises give you a much deeper understanding of how these data types work, the sorts of things they're good and bad at, and an appreciation for how hard library designers have to work? Yes, totally!
Stacks from Deques
Stacks are first-in, last-out structures. Deques let you push/pop from both their front and back. If you keep track of the number of items you've stored in the front/back then you can use the front as one stack and the back as the other, returning NULL items if your counters go to zero.
Why would you do this? Who knows, but read on.
Queues from Stacks
You can implement a queue so that it has O(1) amortized time on all of its operations by using two stacks. When you're placing items on the queue place them in one stack. When you need to pull things off the queue, empty that stack into the other stack and pop from the top of that stack (while filling up the other stack with new incoming items).
Why would you want to do this?
Because, this is, roughly speaking, how you make a queue. Data structures have to be implemented somehow. In a computer you allocate memory starting from a base address and building outwards. Thus, a stack is a very natural data structure because all you need to do is keep track of a single positive offset to know where the top of your stack is.
Implementing a queue directly is more difficult... you are adding items to one end but pulling them off of the other. Two stacks gives you a way to do it.
But why 3 queues?
Because this algorithm (if it exists) ensures that there is a constant bound on the time complexity of a queue operation. With our 2-stack solution on average each item takes O(1) time, but, if we have a really big stack, once in a while there'll be an operation that takes a long time. While that's happening the car crashes, the rocket blows up, or your patient dies.
You don't want a crummy algorithm that gives unpredictable performance.
You want guarantees.
This StackOverflow answer explains that a 3-stack solution isn't known, but that there is a 6-stack solution.
Why Stacks From Deques
Let's return to your first question. As we've seen, there are good reasons to be able to build queues from stacks. For a computer it's a natural way of building a complex data structure from a simple one. It can even offer us performance guarantees.
Stacks from Dequeues doesn't strike me as being practical in a computer. But computer science isn't about computers; it's about finding efficient algorithmic solutions to problems. Maybe you're storing stuff on a multi-directional conveyor belt in a factory. You can program the belt to act like a dequeue and use the dequeue to make stacks. In this context the question makes more sense.
Seems there is no practical usage for these implementations.
The main purpose is to encourage student to invent complex solutions using simple tools - important skill for every qualified developer.
(perhaps the secondary goal is to teach programmer to implement ridiculous visions of the boss :))
I'm currently learning the fundamentals of Algorithms and Data Structures and I am slightly confused about the concepts and the differences between arrays, linked-lists and stacks.
Please correct me if I am wrong: Is stack more like an abstract concept, and arrays and linked-lists are data structures? (Hence we can use either arrays or linked-lists to implement the concept of stack)
Update - 032221
Thank you everyone for helping me out for this question! Back when I asked this question, I had a hard time understanding the overall concept of primitive data types and fundamental data structure (in this case an array) that is offered by each languages.
For example, linked list or queues can be created and implemented using array, but then I thought such linked list and queues still should be called as array (because the foundational data structure that is used behind is technically an array). My thought process was there would be primitive data structures for linked lists or queues that does not use an array. Thus I did not understand quite properly linked-lists or stacks or such data structures are just different patterns and ways that data is organized and configured.
I hope this can help anyone who is having a hard time understanding data structure concept like I did!
Array
A book is an array. You can go to any page by index and quickly go forwards or backwards by any increment you like.
Linked List
A scavenger hunt is a linked list. You can only go from one item to the next, because each item contains the information where to find the next item.
Stack
A pile of letters on your desk is a stack. You can only see the letter lying on top. Removing the top letter reveals the next letter.
From Programming Theory perspective all the tree are Abstract Data Types The fundamental differences between them are their features.
Array - offers a random access to any element in constant time, but removing or adding an element from/into an array is done in linear time
Linked List - offers random access in linear time (that means sequential access). But adding or removing an element is done in constant time.
Stack is a little bit different. It offers you access only to a single element - the top of the stack. The same is valid to removing and adding an element. You can remove only the element that is on the top of the stack and vice versa, add new element on the top of the stack.
You are correct that the stack can be implemented using array or linked list but this is already an implementation point of view. From Theory perspective they are different Abstract Data Types.
In fact if you dig deep enough on the assembly language level you have only 2 options to locate an arbitrary element:
Indexing - Calculate the element location in memory
Indirect addressing - Using a pointer stored in memory to locate the element.
ARRAY - a container that can be called a fixed number of items and those items should be of the same type.
STACK - a list of elements in which an element may be added or deleted only at one end called the top of the stack.
LINKEDLIST - a linear collection of data elements called a node pointing to the next node by means of a pointer.
When does using a doubly linked list seem to be best option in real life scenario? Can someone suggest practical use of it?
Adding to templatetypedef's answer.
You consider following applications :
- A music player which has next and prev buttons.
- Represent a deck of cards in a game.
- The browser cache which allows you to hit the BACK-FORWARD pages.
- Applications that have a Most Recently Used list (a linked list of file names)
- Undo-Redo functionality
Any application where you want to traverse both side from specific point.
In many operating systems, the thread scheduler (the thing that chooses what processes need to run at which times) maintains a doubly-linked list of all the processes running at any time. This makes it easy to move a process from one queue (say, the list of active processes that need a turn to run) into another queue (say, the list of processes that are blocked and waiting for something to release them). The use of a doubly-linked list here allows each of these splices and rewires to run in time O(1) and without any memory allocations, and the doubly-linked-list structure works well for implementing the scheduler using queues (where you only need to pull things out from the front.)
Doubly linked list is used in constructing MRU/LRU (Most/Least Recently Used) cache. You can find the implementation using HashMap and DoublyLinkedList in the link https://www.geeksforgeeks.org/design-a-data-structure-for-lru-cache/
One of the main applications of LRU cache is that it is employed in cases which uses most/least recently accessed items, like in the case of android phone home screen to save the most recently used apps. Here is a link explaining the application
http://www.primarydigit.com/blog/an-application-of-lru-least-recently-used-data-structure-your-phones-home-screen
Hope this helps!
You can think it algorithmically. Like, suppose you want to store some data in which you have to insert some element in between. The best data structure for it would be a linked list as it does the task in O(1).
Next, is suppose you want to access some element from the data. An array would be the best for this as it takes O(1) for accessing an element. But it makes insertion in O(n).
Now, in the linked list we can maintain a map of all the nodes and hence this will make the accessing thing in O(1). The insertion thing was already in O(1).
Now what's remaining is the deletion part. In an array, the deletion is done in O(n) and in the linked list also deletion is done in O(n)(if you have only the element to be deleted).
However, in the linked list if we had the address of the previous node then we could have just deleted the desired node in O(1). Here, comes the use of the doubly linked list.
The above data structure does the three most important things in a system i.e. insertion, deletion and accessing an element in O(1).
I've been coding for quite sometime now. And my work pertains to solving real-world business scenarios. However, I have not really come across any practical usage of some of the data structures like the Linked List, Queues and Stacks etc.
Not even at the business framework level. Of course, there is the ubiquitous HashTable, ArrayList and of late the List...but is there any practical usage of some of the other basic data structures?
It would be great if someone gave a real-world solution where a Doubly Linked List "performs" better than the obvious easily usable counterpart.
Of course it’s possible to get by with only a Map (aka HashTable) and a List. A Queue is only a glorified List but if you use a Queue everywhere you really need a queue then your code gets a lot more readable because nobody has to guess what you are using that List for.
And then there are algorithms that work a lot better when the underlying data structure is not a plain List but a DoublyLinkedList due to the way they have to navigate the list. The same is valid for all other data structures: there’s always a use for them. :)
Stacks can be used for pairing (parseing) such as matching open brackets to closing brackets.
Queues can be used for messaging, or activity processing.
Linked list, or double linked lists can be used for circular navigation.
Most of these algorithms are usually at a lower level than your usual "business" application. For example indices on the database is a variation of a multiply linked list. Implementation of function calling mechanism(or a parse tree) is a stack. Queues and FIFOs are used for servicing network request etc.
These are just examples of collection structures that are optimized for speed in various scenarios.
LIFO-Stack and FIFO-Queue are reasonably abstract (behavioral spec-level) data structures, so of course there are plenty of practical uses for them. For example, LIFO-Stack is a great way to help remove recursion (stack up the current state and loop, instead of making a recursive call); FIFO-Queue helps "buffer up" and "peel away" work nuggets in a coroutine arrangement; etc, etc.
Doubly-linked-List is more of an implementation issue than a behavioral spec-level one, mostly... can be a good way to implement a FIFO-Queue, for example. If you need a sequence with fast splicing and removal give a pointer to one sequence iten, you'll find plenty of other real-world uses, too.
I use queues, linked lists etc. in business solutions all the time.
Except they are implemented by Oracle, IBM, JMS etc.
These constructs are generally at a much lower level of abstaction than you would want while implementing a business solution. Where a business problem would benifit from
such low level constructs (e.g. delivery route planning, production line scheduling etc.) there is usually a package available to do it or you.
I don't use them very often, but they do come up. For example, I'm using a queue in a current project to process asynchronous character equipment changes that must happen in the order the user makes them.
A linked list is useful if you have a subset of "selected" items out of a larger set of items, where you must perform one type of operation on a "selected" item and a default operation or no operation at all on a normal item and the set of "selected" items can change at will (possibly due to user input). Because linked list removal can be done nearly instantaneously (vs. the traversal time it would take for an array search), if the subsets are large enough then it's faster to maintain a linked list than to either maintain an array or regenerate the whole subset by scanning through the whole larger set every time you need the subset.
With a hash table or binary tree, you could search for a single "selected" item, but you couldn't search for all "selected" items without checking every item (or having a separate dictionary for every permutation of selected items, which is obviously impractical).
A queue can be useful if you are in a scenario where you have a lot of requests coming in and you want to make sure to handle them fairly, in order.
I use stacks whenever I have a recursive algorithm, which usually means it's operating on some hierarchical data structure, and I want to print an error message if I run out of memory instead of simply letting the software crash if the program stack runs out of space. Instead of calling the function recursively, I store its local variables in an object, run a loop, and maintain a stack of those objects.