Implement a LinkedListQueue class that uses a singly linked list as its underlying storage. The queue tracks a head pointer for the front item and a tail pointer for the back item, so both enqueue and dequeue run in O(1) time without scanning nodes.
The class must support these methods:
- enqueue(value): create a new node and attach it at the tail
- dequeue(): remove and return the value at the head, or undefined if empty
- peek(): return the head value without removing it, or undefined if empty
- isEmpty(): return true if the queue has no items, false otherwise
When the queue becomes empty after a dequeue, both head and tail must be reset to null. When enqueuing into an empty queue, both head and tail point to the new node.
Input
A sequence of operation names with their arguments, applied to a single LinkedListQueue instance.
Output
A list of return values, one per operation. The constructor returns null.
Examples
Example 1
Input["LinkedListQueue", "enqueue", "enqueue", "peek", "dequeue", "isEmpty"]
[[], [10], [20], [], [], []]
Output[null, null, null, 10, 10, false]
Explanation: After enqueuing 10 and 20, peek returns 10 (the head), dequeue removes and returns 10, and one item (20) remains so isEmpty is false.
Constraints
Enqueue, dequeue, peek, and isEmpty must run in O(1) time.
Dequeue and peek on an empty queue must not throw.