【发布时间】:2021-11-29 23:27:34
【问题描述】:
我正在研究一种算法,当从优先级队列中删除元素时,我想在优先级队列中为具有相同优先级的元素维护 FIFO 顺序。
虽然,我已经看到将自动递增的序列号作为辅助键的解决方案,并用它来打破关系,link here 我需要类似的东西,但我面临的问题是我想要比较的元素- TestItemChange(下面示例中的类)没有实现可比性,我不能(也不想)修改它以使其实现。所以现在,在没有优先级队列中的 FIFO 排序的情况下,我使用的是在创建它时发送的比较器方法。
我现在唯一需要的是在相同优先级时使其成为 FIFO。如何在不使 TestItemChange 实现具有可比性的情况下在以下解决方案中实现自动递增的序列号?我没有在这些界面上做太多工作,这里的任何指导都会很有帮助。
任何线索都会非常有帮助。
代码 --
import java.util.*;
import java.util.stream.Collectors;
public class PriorityQueues {
public static void main(String []args){
TestPriorityQueue obj = new TestPriorityQueue();
obj.build();
}
static class TestPriorityQueue {
private static final Map<String, Integer> PINNED_EVENT_TYPE_PRIORITY_REMOVAL_MAP = new HashMap<>();
public void build(){
PINNED_EVENT_TYPE_PRIORITY_REMOVAL_MAP.put("fashionProduct", 0);
PINNED_EVENT_TYPE_PRIORITY_REMOVAL_MAP.put("bonusContent", 1);
final List<TestTimedItemChange> changesCollection = new ArrayList<>();
final List<TestEvent> eventList = getEvents();
final Map<String, String> eventIdToTypeMap = eventList.stream().collect(
Collectors.toMap(TestEvent::getItemId, TestEvent::getEventType));
final Queue<TestTimedItemChange> pinnedItemsInQuickView =
new PriorityQueue<>(getTimedItemChangeComparator(eventIdToTypeMap));
for (final TestEvent event : eventList) {
final TestTimedItemChange newItemToAdd = buildTimedItemChange(event.getItemId(), event.getStartTime(),
"add");
if (changesCollection.size() >= 4) {
final TestTimedItemChange oldItemToRemove = pinnedItemsInQuickView.peek();
changesCollection.add(buildTimedItemChange(oldItemToRemove.getItemId(),
Math.max(newItemToAdd.getTimePosition(), oldItemToRemove.getTimePosition()),
"remove"));
changesCollection.add(newItemToAdd);
pinnedItemsInQuickView.remove(oldItemToRemove);
pinnedItemsInQuickView.add(newItemToAdd);
} else {
changesCollection.add(newItemToAdd);
pinnedItemsInQuickView.add(newItemToAdd);
}
}
changesCollection.stream().forEach(cc -> System.out.println(cc));
}
private TestTimedItemChange buildTimedItemChange(final String itemId, final long timePosition,
final String itemChangeType) {
TestTimedItemChange testTimedItemChange = new TestTimedItemChange();
testTimedItemChange.setItemId(itemId);
testTimedItemChange.setChangeType(itemChangeType);
testTimedItemChange.setTimePosition(timePosition);
return testTimedItemChange;
}
private static Comparator<TestTimedItemChange> getTimedItemChangeComparator(final Map<String, String> eventIdToTypeMap) {
Comparator<TestTimedItemChange> comparator = new Comparator<TestTimedItemChange>() {
@Override
public int compare(final TestTimedItemChange timedItemChange1, final TestTimedItemChange timedItemChange2) {
final String eventType1 = eventIdToTypeMap.get(timedItemChange1.getItemId());
final String eventType2 = eventIdToTypeMap.get(timedItemChange2.getItemId());
if (eventType1.equals(eventType2)) {
//greater timeposition should be removed last.
return (int) (timedItemChange1.getTimePosition() - timedItemChange2.getTimePosition());
}
//greater priority should be removed last.
return PINNED_EVENT_TYPE_PRIORITY_REMOVAL_MAP.get(eventIdToTypeMap.get(timedItemChange1.getItemId())) -
PINNED_EVENT_TYPE_PRIORITY_REMOVAL_MAP.get(eventIdToTypeMap.get(timedItemChange2.getItemId()));
}
};
return comparator;
}
private List<TestEvent> getEvents() {
List<TestEvent> eventList = new ArrayList<>();
TestEvent event4 = new TestEvent();
event4.setItemId("bts-0");
event4.setEventType("bonusContent");
event4.setStartTime(0L);
eventList.add(event4);
TestEvent event1 = new TestEvent();
event1.setItemId("xst-prd-210");
event1.setEventType("fashionProduct");
event1.setStartTime(0L);
eventList.add(event1);
TestEvent event2 = new TestEvent();
event2.setItemId("xst-prd-211");
event2.setEventType("fashionProduct");
event2.setStartTime(200L);
eventList.add(event2);
TestEvent event3 = new TestEvent();
event3.setItemId("xst-prd-212");
event3.setEventType("fashionProduct");
event3.setStartTime(200L);
eventList.add(event3);
TestEvent event8 = new TestEvent();
event8.setItemId("xst-prd-216");
event8.setEventType("fashionProduct");
event8.setStartTime(200L);
eventList.add(event8);
TestEvent event9 = new TestEvent();
event9.setItemId("xst-prd-217");
event9.setEventType("fashionProduct");
event9.setStartTime(200L);
eventList.add(event9);
TestEvent event10 = new TestEvent();
event10.setItemId("xst-prd-218");
event10.setEventType("fashionProduct");
event10.setStartTime(200L);
eventList.add(event10);
return eventList;
}
private class TestEvent {
private String itemId;
private String eventType;
private Long startTime;
public String getItemId() {
return itemId;
}
public void setItemId(String itemId) {
this.itemId = itemId;
}
public String getEventType() {
return eventType;
}
public void setEventType(String eventType) {
this.eventType = eventType;
}
public Long getStartTime() {
return startTime;
}
public void setStartTime(Long startTime) {
this.startTime = startTime;
}
}
private class TestTimedItemChange {
private String itemId;
private String eventType;
private Long timePosition;
private String changeType;
public String getChangeType() {
return changeType;
}
public void setChangeType(String changeType) {
this.changeType = changeType;
}
public String getItemId() {
return itemId;
}
public void setItemId(String itemId) {
this.itemId = itemId;
}
public String getEventType() {
return eventType;
}
public void setEventType(String eventType) {
this.eventType = eventType;
}
public Long getTimePosition() {
return timePosition;
}
public void setTimePosition(Long timePosition) {
this.timePosition = timePosition;
}
}
}
}
输出 -
TimedItemChange(changeType=add, timePosition=0, itemId=bts-0)
TimedItemChange(changeType=add, timePosition=0, itemId=xst-prd-210)
TimedItemChange(changeType=add, timePosition=200, itemId=xst-prd-211)
TimedItemChange(changeType=add, timePosition=200, itemId=xst-prd-212)
TimedItemChange(changeType=remove, timePosition=200, itemId=xst-prd-210) //correct removal based on starttime/timeposition
TimedItemChange(changeType=add, timePosition=200, itemId=xst-prd-216)
TimedItemChange(changeType=remove, timePosition=200, itemId=xst-prd-212)//wrong removal - should have been 211 as it was inserted before 212
TimedItemChange(changeType=add, timePosition=200, itemId=xst-prd-217)
TimedItemChange(changeType=remove, timePosition=200, itemId=xst-prd-216) //wrong removal
TimedItemChange(changeType=add, timePosition=200, itemId=xst-prd-218)
【问题讨论】:
-
您只能通过使用稳定的排序来完成此操作,而
PriorityQueue不提供它。请参阅 Javadoc。一种解决方法是在键的末尾添加一个序列子键,但如果数据集足够大,则会遇到溢出问题。 -
@user207421 检查我的答案 - 尝试了一些东西并且它的工作。请检查并让我知道是否可以改进 - 另外,还有其他方法可以不添加包装类吗?
-
你完全按照我说的做了。您添加了一个顺序子键。
-
@user207421 你上面提到的溢出问题是什么?是整数限制吗?虽然我们不会有一个大的数据集,但想明白你的意思。
-
使 PQ 的优先级成为实际优先级和添加到 PQ 的时间的元组。如果优先级不同,则比较器应使用优先级,但如果优先级相同,则按时间打破平局。由于“时间”是相对的输入顺序,您可以只使用递增计数器作为代理。
标签: java comparator priority-queue fifo