Implementing a Reactive Priority Queue in Vue.js (TypeScript)
This challenge focuses on building a fundamental data structure, a priority queue, within a Vue.js application using TypeScript. A priority queue is essential for scenarios where elements need to be processed based on their priority, not just the order they were added. You'll create a reusable Vue component that allows users to add items with associated priorities and then retrieve the highest priority item.
Problem Description
Your task is to create a Vue.js component that encapsulates a priority queue. This component should allow users to:
- Add items: Users should be able to add new items to the queue. Each item will have a
value(any data type) and apriority(a number, where lower numbers indicate higher priority). - Retrieve highest priority item: Users should be able to dequeue the item with the highest priority from the queue.
- Observe queue state: The component should be reactive, meaning that any changes to the queue (adding or removing items) should be reflected in the UI if bound to it.
Key Requirements:
- TypeScript: The entire implementation must be in TypeScript.
- Vue Component: Create a functional or options API Vue component.
- Priority Queue Logic: Implement the core priority queue logic. You can choose your preferred underlying implementation (e.g., a sorted array, a binary heap), but it must correctly maintain priority order.
- Reactivity: Ensure that when items are added or removed, any Vue bindings to the queue's state update accordingly.
- Clear API: Provide a simple and intuitive API for interacting with the priority queue component from its parent.
Expected Behavior:
- When an item with a higher priority (lower number) is added, it should be placed before lower priority items.
- Dequeuing should always return the item with the smallest priority number.
- If multiple items have the same highest priority, any one of them can be returned.
Edge Cases to Consider:
- Empty Queue: What happens when
dequeueis called on an empty queue? - Duplicate Priorities: How are items with identical priorities handled?
- Non-numeric Priorities: While the problem specifies numbers, consider how you might handle or validate non-numeric inputs for priority (though strict numeric input is acceptable for this challenge).
Examples
Example 1: Basic Usage
// Parent Component (Conceptual)
<template>
<div>
<PriorityQueue @item-added="handleItemAdded" @item-dequeued="handleItemDequeued">
<button @click="addItem('Task A', 2)">Add Task A (Priority 2)</button>
<button @click="addItem('Task B', 1)">Add Task B (Priority 1)</button>
<button @click="addItem('Task C', 3)">Add Task C (Priority 3)</button>
<button @click="dequeueItem">Dequeue Highest Priority</button>
</PriorityQueue>
<p>Queue State: {{ queueItems }}</p>
<p>Dequeued Item: {{ lastDequeuedItem }}</p>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import PriorityQueue from './components/PriorityQueue.vue'; // Assuming you create this component
export default defineComponent({
components: {
PriorityQueue,
},
setup() {
const queueItems = ref<any[]>([]); // To display queue state for debugging/visualization
const lastDequeuedItem = ref<any>(null);
const handleItemAdded = (items: any[]) => {
queueItems.value = items;
};
const handleItemDequeued = (item: any) => {
lastDequeuedItem.value = item;
// You might also want to update queueItems.value here if the component doesn't emit the full updated list
};
return {
queueItems,
lastDequeuedItem,
handleItemAdded,
handleItemDequeued,
// Methods to interact with the PriorityQueue component
addItem: (value: any, priority: number) => {
// Assume PriorityQueue component has an 'add' method
// This part would depend on how you expose the PriorityQueue's methods
console.log(`Attempting to add: ${value} with priority ${priority}`);
},
dequeueItem: () => {
// Assume PriorityQueue component has a 'dequeue' method
console.log('Attempting to dequeue');
},
};
},
});
</script>
Output (after clicking buttons in order: Add Task A, Add Task B, Add Task C, Dequeue Highest Priority):
- Console Logs:
Attempting to add: Task A with priority 2Attempting to add: Task B with priority 1Attempting to add: Task C with priority 3Attempting to dequeue
queueItems.value(after all adds):[{ value: 'Task B', priority: 1 }, { value: 'Task A', priority: 2 }, { value: 'Task C', priority: 3 }](order might vary slightly based on internal implementation for equal priorities, but 'Task B' should be first).lastDequeuedItem.value(after dequeue):{ value: 'Task B', priority: 1 }queueItems.value(after dequeue):[{ value: 'Task A', priority: 2 }, { value: 'Task C', priority: 3 }]
Example 2: Handling Empty Queue
// Parent Component (Conceptual) - continuing from Example 1
<template>
<div>
<PriorityQueue @item-added="handleItemAdded" @item-dequeued="handleItemDequeued">
<button @click="dequeueItem">Dequeue Highest Priority</button>
</PriorityQueue>
<p>Queue State: {{ queueItems }}</p>
<p>Dequeued Item: {{ lastDequeuedItem }}</p>
<p>Queue Empty Message: {{ emptyMessage }}</p>
</div>
</template>
<script lang="ts">
// ... (previous script setup)
import { ref } from 'vue'; // Import ref if not already
export default defineComponent({
// ... components and other setup
setup() {
// ... existing refs and methods
const emptyMessage = ref<string>('');
const handleItemDequeued = (item: any) => {
if (item === null) { // Assuming dequeue on empty returns null or undefined
emptyMessage.value = 'Queue is empty!';
lastDequeuedItem.value = null;
} else {
lastDequeuedItem.value = item;
emptyMessage.value = '';
}
};
return {
// ... existing return values
emptyMessage,
handleItemDequeued,
// ... existing addItem and dequeueItem methods
};
},
});
</script>
Output (after clicking "Dequeue Highest Priority" on an empty queue):
queueItems.value:[]lastDequeuedItem.value:null(orundefined)emptyMessage.value:"Queue is empty!"
Constraints
- Priority Values: Priority values will be integers.
- Item Values: Item values can be of any JavaScript type (string, number, object, etc.).
- Queue Size: The queue can theoretically hold an unlimited number of items.
- Performance: For typical use cases (up to thousands of items), adding and removing items should ideally be efficient (e.g., O(log n) or O(n) depending on implementation choice).
Notes
- Consider how you will expose the
addanddequeuemethods from yourPriorityQueuecomponent to its parent. UsingdefineExposein the Composition API or exposing methods on the component instance in the Options API are common approaches. - You'll likely need to emit events from the
PriorityQueuecomponent to inform the parent about changes (e.g.,item-added,item-dequeued) so the parent can update its own state or UI. - Think about the structure of the items in the queue. A simple object like
{ value: T, priority: number }is recommended. - A sorted array implementation is simpler but less performant for large queues (O(n) for add). A binary heap implementation offers better performance (O(log n) for both add and remove) but is more complex to implement. Choose what best suits your understanding and time.
- Vue's reactivity system will automatically handle updating the UI if you expose and manage the queue's state correctly within the component.