Module 1 (Deque) - AlproITS/StrukturData GitHub Wiki
Deque
Terminology
- Head - the first node/located in the front of the deque.
- Tail - the last node/located at the back of the deque.
Definition
Deque (Double-ended Queue) is a linear data structure that is similar with the Doubly Linked List data structure as well as a variation of the Queue. One thing that differentiates a Deque with a Queue is the way how a data is added or removed. Unlike Queues, that can only add a data at the back and remove the data in the front of the queue, Deques can add/remove data at the back or in the front.
Basic Operation
- isEmpty - to check whether a Deque is empty or not.
- pushFront - to add a new data at the front.
- pushBack - to add new data at the back.
- front - to get the data located at the front.
- back - to get the data located at the back.
- popFront - to remove the data located at the front.
- popBack - to remove a data located at the back.
The Time Complexity for the above operations are constant O(1).
Deque's Use Cases
Deques are commonly used to solve problems with a Sliding Window characteristic. On such problems, we need to remove both data located at the front and at the back. An example of a Sliding Window problem is to search the maximum value within a subarray with a certain size.
Deque
ADT Implementation: A complete implementation of Deque
can be accessed here.
As mentioned earlier, Deques can be implemented by modifying the Doubly Linked List data structure where two pointers, tail/rear
is used to refer to the node located at the back and head/front
to refer to the node located at the front.
-
Nodes within a Deque can be represented by a struct named Node Representation
DListNode
that stores anint
and a referenced to the next and previous nodes.typedef struct dnode_t { int data; struct dnode_t \ *next, *prev; } DListNode;
-
Deques have two pointers within their structures, that is Deque Structure
head
andtail
.typedef struct deque_t { DListNode \ *_head, *_tail; unsigned _size; } Deque;
-
To check whether a Deque is empty or not, check whether both the isEmpty
head
andtail
are pointing toNULL
or not.bool deq_isEmpty(Deque *deque) { return (deque->_head == NULL && \ deque->_tail == NULL); }
-
to do a pushFront, do the following steps: pushFront
- make a new node
- if the Deque is empty, make that new node as the
head
and thetail
. - if it is not, make the next of the new node points to the current
head
and the prev of the currenthead
to the new node. - make the
head
points to the new node.
void deq_pushFront(Deque *deque, int value) { DListNode *newNode = __dlist_createNode(value); if (newNode) { deque->_size++; if (deq_isEmpty(deque)) { deque->_head = newNode; deque->_tail = newNode; return; } newNode->next = deque->_head; deque->_head->prev = newNode; deque->_head = newNode; } }
-
Follow the following steps to do a pushBack. pushBack
- make a new node.
- if the Deque is empty, make the new node as both the
head
and thetail
. - if it is not empty, make the prev of the new node to point at the current
tail
node, and the next of the currenttail
to point at the new node. - make the
tail
node to point at the new node.
void deq_pushBack(Deque *deque, int value) { DListNode *newNode = __dlist_createNode(value); if (newNode) { deque->_size++; if (deq_isEmpty(deque)) { deque->_head = newNode; deque->_tail = newNode; return; } deque->_tail->next = newNode; newNode->prev = deque->_tail; deque->_tail = newNode; } }
-
front
int deq_front(Deque *deque) { if (!deq_isEmpty(deque)) { return (deque->_head->data); } return 0; }
-
rear
int deq_back(Deque *deque) { if (!deq_isEmpty(deque)) { return (deque->_tail->data); } return 0; }
-
To do a popFront, follow these steps: popFront
- store the current
head
node within a temporary variable - make the 'head' to refer to the next of the current 'head'
- remove the node within the temporary variable
- if the
head
is empty, the thetail
should be too.
void deq_popFront(Deque *deque) { if (!deq_isEmpty(deque)) { DListNode *temp = deque->_head; if (deque->_head == deque->_tail) { deque->_head = NULL; deque->_tail = NULL; free(temp); } else { deque->_head = deque->_head->next; deque->_head->prev = NULL; free(temp); } deque->_size--; } }
- store the current
-
To do a popBack, follow these steps: popBack
- store the current
tail
within a temporary variable. - make the
tail
to refer to the prev of the currenttail
. - remove the node within the temporary variable
- if the
tail
is empty, then thehead
should be too.
void deq_popBack(Deque *deque) { if (!deq_isEmpty(deque)) { DListNode *temp; if (deque->_head == deque->_tail) { temp = deque->_head; deque->_head = NULL; deque->_tail = NULL; free(temp); } else { temp = deque->_tail; deque->_tail = deque->_tail->prev; deque->_tail->next = NULL; free(temp); } deque->_size--; } }
- store the current