【问题标题】:Make Priority Queues follow FIFO order when priority is same in Java当 Java 中的优先级相同时,使优先级队列遵循 FIFO 顺序
【发布时间】: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


【解决方案1】:

我工作了,这似乎工作了 - 基本上包装了 TestTimeItemChange 类 - 入口类 - 并单独获取比较器。

有没有其他不添加包装类的方法?

工作代码 -

package com.amazon.atv.xray.vending.service.assemblerV2.builder.change;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
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 class Entry {

        private final static AtomicInteger seq = new AtomicInteger(0);
        final int order;
        final TestTimedItemChange timedItemChange;

        public int getOrder() {
            return order;
        }

        public TestTimedItemChange getTimedItemChange() {
            return timedItemChange;
        }

        public Entry(final TestTimedItemChange timedItemChange) {
            this.timedItemChange = timedItemChange;
            order = seq.incrementAndGet();
        }

        @Override
        public String toString() {
            StringBuilder ret = new StringBuilder();
            ret.append("Entry(");

            ret.append("timedItemChange=");
            ret.append(timedItemChange.toString());
            ret.append(", ");

            ret.append("seq=");
            ret.append(String.valueOf(order));

            ret.append(")");

            return ret.toString();
        }

    }

   private static Comparator<Entry> getTimedItemChangeComparatorFIFO(final Map<String, String> eventIdToTypeMap) {
        Comparator<Entry> comparator = new Comparator<Entry>() {
            @Override
            public int compare(final Entry entry1, final Entry entry2) {
                int result = PINNED_EVENT_TYPE_PRIORITY_REMOVAL_MAP.get(eventIdToTypeMap.get(entry1.getTimedItemChange().getItemId())) -
                        PINNED_EVENT_TYPE_PRIORITY_REMOVAL_MAP.get(eventIdToTypeMap.get(entry2.getTimedItemChange().getItemId()));
                if (result == 0)
                    return Integer.compare(entry1.getOrder(), entry2.getOrder());
                return result;
            }
        };
        return comparator;
    }

    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<Entry> pinnedItemsInQuickView =
                new PriorityQueue<>(getTimedItemChangeComparatorFIFO(eventIdToTypeMap));

        for (final TestEvent event : eventList) {
            final TestTimedItemChange newItemToAdd = buildTimedItemChange(event.getItemId(), event.getStartTime(),
                    "add");

            if (changesCollection.size() >= 4) {
                //System.out.println(pinnedItemsInQuickView.remove());
                final TestTimedItemChange oldItemToRemove = pinnedItemsInQuickView.remove().getTimedItemChange();
                changesCollection.add(buildTimedItemChange(oldItemToRemove.getItemId(),
                        Math.max(newItemToAdd.getTimePosition(), oldItemToRemove.getTimePosition()),
                        "remove"));
                changesCollection.add(newItemToAdd);
                //pinnedItemsInQuickView.remove();
                pinnedItemsInQuickView.add(new Entry(newItemToAdd));

            } else {
                changesCollection.add(newItemToAdd);
                pinnedItemsInQuickView.add(new Entry(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 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;
        }

        @Override
        public String toString() {
            StringBuilder ret = new StringBuilder();
            ret.append("XrayEvent(");

            ret.append("startTime=");
            ret.append(String.valueOf(startTime));
            ret.append(", ");

            ret.append("eventType=");
            ret.append(String.valueOf(eventType));
            ret.append(", ");

            ret.append("itemId=");
            ret.append(String.valueOf(itemId));
            ret.append(")");
            return ret.toString();
        }
    }

    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;
        }

        @Override
        public String toString() {
            StringBuilder ret = new StringBuilder();
            ret.append("TimedItemChange(");

            ret.append("changeType=");
            ret.append(String.valueOf(changeType));
            ret.append(", ");

            ret.append("timePosition=");
            ret.append(String.valueOf(timePosition));
            ret.append(", ");

            ret.append("itemId=");
            ret.append(String.valueOf(itemId));
            ret.append(")");

            return ret.toString();
        }
    }
}

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-13
    • 1970-01-01
    相关资源
    最近更新 更多