3

I have been asked to implement a doubly linked queue, but I know a singly-linked queue is straightforward with all of its major functions running in big-Theta 1. I am basically talking about FIFO implementation (not including special queues like deque).

I have seen other people implementing the queue using doubly-link implementation and I know this consumes more storage since each node requires 2 pointers (prev & next).

Is there any advantage of doubly linked queue over singly-linked queue?!

TylerH
  • 20,799
  • 66
  • 75
  • 101
  • Have you heared about double ended queue? , In this user is allowed to enque and deque from both ends. This is application specific . – Lalit Verma Nov 29 '17 at 13:11
  • You can go through this link for the same http://www.geeksforgeeks.org/doubly-linked-list/ – ankitkhandelwal185 Nov 29 '17 at 13:14
  • I know double-ended queue (deque) but my concern is in the normal queue implementation of FIFO @LalitVerma – Ellysherh Kingdom Nov 29 '17 at 13:59
  • For a normal list structure, there are always advantages of implementing doubly-linked list but my question is based on the queue implementation since the functions are different from the list @iwayankit – Ellysherh Kingdom Nov 29 '17 at 14:02

2 Answers2

2

You do not need a Doubly LL over a Double ended LL. A double ended LL (has pointer to head and tail) suffices.

For FIFO, the main operations are enqueue and dequeue. In linked list terms, this is add_to_end and remove_from_front. Both of these are O(1) operations with a double ended linked list.

If you needed a data structure that could operate both as a queue and a stack, then you would need a doubly linked list to get O(1) operations. The main operation that would take O(n) without a doubly linked list is remove_from_end/pop. The reason for this is that you would have to find the node one previous from the last (node3 in example below), set it to the tail and then remove its pointer to the node that you are removing. With a doubly LL, it is as simple as tail.prev to find this node; however, with a double ended LL, you would have to do a O(n) traversal to find that node.

First 1 - 2 - 3 - 4 Last

def remove_from_end():
# get node4 and remove node4 from being the tail. O(1) time as you have a pointer to the tail in a double ended LL.
# set tail node3 and remove the .next from node3 to node4. If you don't have .prev on node4, then it would take O(n) to find node3
JaTo
  • 2,742
  • 4
  • 29
  • 38
  • Why wouldn't you use the start of the double ended LL as the open end of the stack? With a double ended LL, you can insert in O(1) time at both ends, and you can also remove from the start in O(1) – Stefan Octavian Apr 22 '22 at 16:53
0

The advantage is that you can iterate in either direction on a doubly linked list. Also, if the data objects are sizeable, then the extra memory overhead is not a large percentage.

Dragonthoughts
  • 2,180
  • 8
  • 25
  • 28
  • For the normal queue operations (enqueue, dequeue, also clear, get front/rear value and get length, isEmpty, isFull, etc), they do not need you to iterate in both directions. They even do not need you to iterate in any direction except for printing out the queue and other minor functions. I still don't see the advantage on this @Dragonthoughts – Ellysherh Kingdom Nov 29 '17 at 14:10
  • How do you deque from either end with a singly linked queue, without iterating to the end from the start? You need to know what points to your end to make it into your new end. – Dragonthoughts Nov 29 '17 at 14:13
  • That's why I included the words "major functions" of the queue in my question. You are talking about a special queue (deque), but my problem is mainly with FIFO implementation, maybe let me update my question to be more clear – Ellysherh Kingdom Nov 29 '17 at 14:19
  • If you are creating a FIFO implementation, you are adding at one end and dequeuing at the other. How do you keep your pointers in order without iterating to the end for one operation in a singly linked structure? – Dragonthoughts Nov 29 '17 at 15:16
  • @Dragonthoughts What do you want to do with the pointers? I don't need to touch anything in the middle. I only need pointers to the first and to the last element. The current last element points to the next one, if I dequeue it I get the next "last" pointer from there. When I insert at the front I have a pointer to that item too to change its "next" property to the one I just inserted. No need to iterate or to touch anything in between. – Mörre Jan 21 '19 at 09:44
  • When you deque, using the "last pointer", how do you determine the new value for your "last pointer"? The new "last pointer" should be the pointer for the itme prior to the one that you are returning, so on a singly linked list, you will need to iterate to that element, to find it's address, and do whatever housekeeping is necessary to prevent it pointing to the dequeued item. – Dragonthoughts Jan 21 '19 at 10:15
  • @Dragonthoughts What if you dequeue from the head, and enqueue at the tail. A SLL would work right? Since the tail isn't removed, only the head. – user4779 Mar 22 '22 at 11:03
  • Not quite, @user4779 because on an SLL, you don't necessarily have a pointer to the last element, although it would be a good idea for that scenario, you are dependent on the library implementation, unless you write your own. – Dragonthoughts Mar 23 '22 at 11:24