Algorithm 具有动态项目优先级的优先级队列

Algorithm 具有动态项目优先级的优先级队列,algorithm,heap,priority-queue,Algorithm,Heap,Priority Queue,我需要实现一个优先级队列,其中队列中某个项目的优先级可以更改,并且队列会自行调整,以便始终以正确的顺序删除项目。我对如何实现这一点有一些想法,但我确信这是一种非常常见的数据结构,因此我希望我可以使用比我更聪明的人的实现作为基础 有谁能告诉我这种优先级队列的名称,让我知道要搜索什么,或者更好的是,给我指一个实现吗?给您,包括的一个实现 然而,这听起来像是一个家庭作业问题,因此如果是这样,我建议你先尝试自己完成这些想法,如果你在某个地方陷入困境,需要一个指向正确方向的指针,那么可能会参考其他人的实现

我需要实现一个优先级队列,其中队列中某个项目的优先级可以更改,并且队列会自行调整,以便始终以正确的顺序删除项目。我对如何实现这一点有一些想法,但我确信这是一种非常常见的数据结构,因此我希望我可以使用比我更聪明的人的实现作为基础

有谁能告诉我这种优先级队列的名称,让我知道要搜索什么,或者更好的是,给我指一个实现吗?

给您,包括的一个实现


然而,这听起来像是一个家庭作业问题,因此如果是这样,我建议你先尝试自己完成这些想法,如果你在某个地方陷入困境,需要一个指向正确方向的指针,那么可能会参考其他人的实现。这样,您就不太可能“偏袒”其他程序员使用的精确编码方法,而更可能理解为什么包含每段代码以及它是如何工作的。有时,执行“复制和粘贴”的等效解释可能有点太诱人了。

标准二进制堆支持5个操作(下面的示例假设最大堆):


如您所见,在max堆中,您可以增加任意密钥。在最小堆中,可以减少任意密钥。不幸的是,您不能双向更改密钥,但这样可以吗?如果您需要双向更改密钥,那么您可能需要考虑使用a。

我建议您首先尝试头部插入法,以更新优先级:

  • 从队列中删除该项目
  • 用新的优先级重新插入它
在C++中,这可以使用<代码> STD::MulyOxMult来完成,重要的是对象必须记住它存储在结构中的位置,以便能够有效地删除自身。对于重新插入,这是很困难的,因为你不能假定你知道任何关于优先级的事情

class Item;

typedef std::multi_map<int, Item*> priority_queue;

class Item
{
public:
  void add(priority_queue& queue);
  void remove();

  int getPriority() const;
  void setPriority(int priority);

  std::string& accessData();
  const std::string& getData() const;

private:
  int mPriority;
  std::string mData;

  priority_queue* mQueue;
  priority_queue::iterator mIterator;
};

void Item::add(priority_queue& queue)
{
  mQueue = &queue;
  mIterator = queue.insert(std::make_pair(mPriority,this));
}

void Item::remove()
{
  mQueue.erase(mIterator);
  mQueue = 0;
  mIterator = priority_queue::iterator();
}

void Item::setPriority(int priority)
{
  mPriority = priority;
  if (mQueue)
  {
    priority_queue& queue = *mQueue;
    this->remove();
    this->add(queue);
  }
}
类项目;
typedef std::多映射优先级队列;
类项目
{
公众:
无效添加(优先级队列和队列);
无效删除();
int getPriority()常量;
无效设置优先级(int优先级);
std::string&accessData();
常量std::string&getData()常量;
私人:
国际优先权;
std::字符串mData;
优先级队列*mQueue;
优先级队列::迭代器斜接器;
};
无效项::添加(优先级队列和队列)
{
mQueue=&queue;
mIterator=queue.insert(std::make_pair(mPriority,this));
}
无效项::删除()
{
mQueue.erase(斜接器);
mQueue=0;
mIterator=priority_queue::iterator();
}
无效项::设置优先级(整数优先级)
{
优先权=优先权;
if(mQueue)
{
优先级队列&queue=*mQueue;
此->删除();
此->添加(队列);
}
}

我正在寻找完全相同的东西

以下是我的一些想法:

  • 由于项目的优先级不断变化, 在检索项目之前对队列进行排序是没有意义的
  • 因此,我们应该忘记使用优先级队列。和“部分”排序 在检索项目时使用容器
  • 并从以下STL排序算法中进行选择: A.隔断 B稳定分区 Cn_元素 D部分排序 E部分排序拷贝 F分类 G稳定排序

    分区、稳定分区和第n个元素是线性时间排序算法,应该是我们的首选


    但是,官方Java库中似乎没有提供这些算法。因此,我建议您使用java.util.Collections.max/min来做您想做的事情。

    像其他人建议的那样,这样的优先级队列通常使用二进制堆数据结构来实现,通常使用数组表示,但也可以使用二叉树。实际上,增加或减少堆中元素的优先级并不难。如果知道要在从队列中弹出下一个元素之前更改许多元素的优先级,可以暂时关闭动态重新排序,在堆的末尾插入所有元素,然后在需要弹出元素之前重新排序整个堆(代价是O(n))。关于堆的重要一点是,将数组放入堆顺序只需O(n),而排序只需O(n logn)

    我在一个具有动态优先级的大型项目中成功地使用了这种方法

    class Item;
    
    typedef std::multi_map<int, Item*> priority_queue;
    
    class Item
    {
    public:
      void add(priority_queue& queue);
      void remove();
    
      int getPriority() const;
      void setPriority(int priority);
    
      std::string& accessData();
      const std::string& getData() const;
    
    private:
      int mPriority;
      std::string mData;
    
      priority_queue* mQueue;
      priority_queue::iterator mIterator;
    };
    
    void Item::add(priority_queue& queue)
    {
      mQueue = &queue;
      mIterator = queue.insert(std::make_pair(mPriority,this));
    }
    
    void Item::remove()
    {
      mQueue.erase(mIterator);
      mQueue = 0;
      mIterator = priority_queue::iterator();
    }
    
    void Item::setPriority(int priority)
    {
      mPriority = priority;
      if (mQueue)
      {
        priority_queue& queue = *mQueue;
        this->remove();
        this->add(queue);
      }
    }
    

    下面是我的一个参数化模型的实现

    谢谢Dav,但这是一个标准优先级队列。如果我向队列中添加了一个项目,并且它的优先级发生了更改(在队列之外),那么队列的顺序可能不正确。换句话说,标准优先级队列仅在将项目添加到队列时对其进行排序,而不是稍后。我需要实现一个队列,随着其项目优先级的更新而更新。另外,这不是一个家庭作业问题,我需要把它作为一些模拟软件的一部分来实现。我对如何实现它有一些想法,但想看看是否有更好的方法。可以在这种情况下,我建议寻找Dijkstra算法的示例实现,该算法(如果以最有效的形式实现)需要一个可重排序的优先级队列,因此可能会有您想要的。请参阅并感谢Matthieu,我曾想过使用这种方法,但由于更新频率太高,无法满足我的需要。我最终使用了一个实现,该实现包括一个字典,将项映射到队列中的索引,然后在队列上有一个方法UpdatePosition(Item Item),该方法查找项索引,然后将其冒泡到新位置。然后,队列会有一个项目注册所针对的事件,以便在优先级发生变化时通知队列。这似乎很有效。如果您首先需要搜索希望增加的元素,我不知道二进制堆如何有效地支持增加密钥。由于堆中没有排序,因此查找元素需要线性时间。您必须有一个引用