【问题标题】:Difference between priority queue and a heap优先级队列和堆之间的区别
【发布时间】:2013-09-30 08:34:40
【问题描述】:

似乎优先级队列只是一个具有正常队列操作(如插入、删除、顶部等)的堆。这是解释优先级队列的正确方法吗?我知道您可以用不同的方式构建优先级队列,但是如果我要从堆中构建优先级队列,是否有必要创建一个优先级队列类并给出构建堆和队列操作的说明,或者真的不需要构建上课?

我的意思是,如果我有一个构建堆的函数和执行插入和删除等操作的函数,我是否需要将所有这些函数放在一个类中,或者我可以通过在 @987654324 中调用它们来使用指令吗? @。

我想我的问题是,拥有一组函数是否等同于将它们存储在某个类中并通过一个类使用它们,或者只是使用函数本身。

下面是优先级队列实现的所有方法。这足以将其称为实现还是我需要将其放入指定的优先级队列类中?

#ifndef MAX_PRIORITYQ_H
#define MAX_PRIORITYQ_H
#include <iostream>
#include <deque>
#include "print.h"
#include "random.h"

int parent(int i)
{
    return (i - 1) / 2;
}

int left(int i)
{
    if(i == 0)
        return 1;
    else
        return 2*i;
}

int right(int i)
{
    if(i == 0)
        return 2;
    else
        return 2*i + 1;
}

void max_heapify(std::deque<int> &A, int i, int heapsize)
{
    int largest;
    int l = left(i);
    int r = right(i);
    if(l <= heapsize && A[l] > A[i])
        largest = l;
    else
        largest = i;
    if(r <= heapsize && A[r] > A[largest])
        largest = r;
    if(largest != i) {
        exchange(A, i, largest);
        max_heapify(A, largest, heapsize);
        //int j = max_heapify(A, largest, heapsize);
        //return j;
    }
    //return i;
}

void build_max_heap(std::deque<int> &A)
{
    int heapsize = A.size() - 1;
    for(int i = (A.size() - 1) / 2; i >= 0; i--)
        max_heapify(A, i, heapsize);
}

int heap_maximum(std::deque<int> &A)
{
    return A[0];
}

int heap_extract_max(std::deque<int> &A, int heapsize)
{
    if(heapsize < 0)
        throw std::out_of_range("heap underflow");
    int max = A.front();
    //std::cout << "heapsize : " << heapsize << std::endl;
    A[0] = A[--heapsize];
    A.pop_back();
    max_heapify(A, 0, heapsize);
    //int i = max_heapify(A, 0, heapsize);
    //A.erase(A.begin() + i);
    return max;
}

void heap_increase_key(std::deque<int> &A, int i, int key)
{
    if(key < A[i])
        std::cerr << "New key is smaller than current key" << std::endl;
    else {
        A[i] = key;
        while(i > 1 && A[parent(i)] < A[i]) {
            exchange(A, i, parent(i));
            i = parent(i);
        }
    }
}

void max_heap_insert(std::deque<int> &A, int key)
{
    int heapsize =  A.size();
    A[heapsize] = std::numeric_limits<int>::min();
    heap_increase_key(A, heapsize, key);
}

【问题讨论】:

  • 不,这不太对。您是否阅读过相应的维基百科文章?
  • 使用堆是实现优先级队列的一种方式。这是一种流行且有效的方法,但它不是唯一的方法,因此您可以拥有一个在没有堆的情况下实现的优先级队列。
  • 这是两种不同的抽象类。优先级队列是一种抽象数据类型,就像保存优先级的队列一样,因此当您添加到队列元素时,它不会到达队列的最末端,而是到达“适合”的位置。堆,一般来说是一块用于存储东西的内存。
  • @Grzegorz:(至少)有两种“堆”。您提到的“内存池”以及堆数据结构。
  • @Sebastian 是的,不幸的是,这个词已经超载了。见the Wikipedia disambiguation pageheap data structurethe heap aka the free store.

标签: c++ algorithm heap priority-queue


【解决方案1】:

优先级队列是abstract datatype。它是描述特定接口和行为的简写方式,不涉及底层实现。

堆是data structure。它是一种特殊的数据存储方式的名称,可以使某些操作非常高效。

恰好堆是实现优先级队列的一个很好的数据结构,因为堆数据结构高效的操作是优先级队列接口需要的操作。

【讨论】:

  • 或者可以说“堆”是一组数据结构,它们的共同点是它们都维护“堆属性”,但它们以不同的方式实现这一点,从而产生了不同的性能特征。跨度>
  • “对底层实现只字未提”?如果没有在构造函数中明确定义,它被实现为 std::vector,不是吗?
  • @computer:C++ 标准对std::priority_queue 类模板的底层实现做出了某些承诺,但我在这里谈论的是通用计算机科学,并不特定于任何语言或库。
  • 这是一个很好的答案。
  • 非常感谢
【解决方案2】:

拥有一个具有您需要的接口的类(只需插入和 pop-max?)有其优势。

  • 您可以稍后交换实现(例如,列表而不是堆)。
  • 阅读使用队列的代码的人不需要理解堆数据结构更难的接口。

我想我的问题是拥有一个函数集合是否是 相当于将它们存储在某个类中并通过 类或仅使用函数本身。

如果您只考虑“我的程序的行为方式”,它基本上是等价的。但就“人类读者理解我的程序有多容易”而言,它并不等同

【讨论】:

    【解决方案3】:

    优先级队列这个术语是指用于对其元素的优先级排序的通用数据结构。有多种方法可以实现这一点,例如,各种有序树结构(例如,splay 树工作得相当好)以及各种堆,例如 d-heaps 或 Fibonacci heaps。从概念上讲,是一种树结构,其中每个节点的权重不小于路由到该节点的子树中任何节点的权重。

    【讨论】:

    • 确认一下,说堆是一种优先级队列对吗?
    • @AdityaPrakash Heaps 可用于实现优先级队列。可能还有其他用途,尽管我想不出任何不能被视为优先级队列的用途……
    【解决方案4】:

    C++ 标准模板库提供了 make_heap、push_heap 和堆的 pop_heap 算法(通常实现为二进制 heaps),它在任意随机访问迭代器上运行。它对待 迭代器作为对数组的引用,并使用数组到堆 转换。它还提供了容器适配器priority_queue, 它将这些设施包装在一个类似容器的类中。然而,有 对减少/增加键操作没有标准支持。

    priority_queue 指的是完全由可能对其执行的操作定义的抽象数据类型。因此,在 C++ 中,STL prioroty_queuesequence adapters 之一 - 基本容器的适配器(vector、list 和 deque 是基本的,因为它们不能在不损失效率的情况下相互构建),在 @ 中定义987654323@ 标头(实际上是&lt;bits/stl_queue.h&gt; 在我的情况下)。从它的定义可以看出,(正如 Bjarne Stroustrup 所说):

    容器适配器为容器提供了一个受限接口。在 特别是,适配器不提供迭代器;他们的目的是 仅通过他们的专用接口使用。

    在我的实现中,prioroty_queue 被描述为

    /**
       *  @brief  A standard container automatically sorting its contents.
       *
       *  @ingroup sequences
       *
       *  This is not a true container, but an @e adaptor.  It holds
       *  another container, and provides a wrapper interface to that
       *  container.  The wrapper is what enforces priority-based sorting 
       *  and %queue behavior.  Very few of the standard container/sequence
       *  interface requirements are met (e.g., iterators).
       *
       *  The second template parameter defines the type of the underlying
       *  sequence/container.  It defaults to std::vector, but it can be
       *  any type that supports @c front(), @c push_back, @c pop_back,
       *  and random-access iterators, such as std::deque or an
       *  appropriate user-defined type.
       *
       *  The third template parameter supplies the means of making
       *  priority comparisons.  It defaults to @c less<value_type> but
       *  can be anything defining a strict weak ordering.
       *
       *  Members not found in "normal" containers are @c container_type,
       *  which is a typedef for the second Sequence parameter, and @c
       *  push, @c pop, and @c top, which are standard %queue operations.
       *  @note No equality/comparison operators are provided for
       *  %priority_queue.
       *  @note Sorting of the elements takes place as they are added to,
       *  and removed from, the %priority_queue using the
       *  %priority_queue's member functions.  If you access the elements
       *  by other means, and change their data such that the sorting
       *  order would be different, the %priority_queue will not re-sort
       *  the elements for you.  (How could it know to do so?)
    

    模板:

      template<typename _Tp, typename _Sequence = vector<_Tp>,
           typename _Compare  = less<typename _Sequence::value_type> >
        class priority_queue
        {
    

    与此相反,heap 描述了它的元素是如何被获取并存储在内存中的。 It is a (tree based) data structure,其他是数组,哈希表,结构体,联合体,集合...,另外满足堆属性:所有节点要么[大于或​​等于]要么[小于或等于] 它的每个子代,根据为堆定义的比较谓词。

    所以在我的堆头中我没有找到堆容器,而是一组算法

      /**
       * @defgroup heap_algorithms Heap Algorithms
       * @ingroup sorting_algorithms
       */ 
    

    喜欢:

    • __is_heap_until
    • __is_heap
    • __push_heap
    • __adjust_heap
    • __pop_heap
    • make_heap
    • 排序堆

    所有这些(不包括__is_heap,注释为“这个函数是一个扩展,不是C++标准的一部分”)描述为

       *  @ingroup heap_algorithms
       *
       *  This operation... (what it  does)
    

    【讨论】:

      【解决方案5】:

      不是真的。名称中的“优先级”源于队列中条目的优先级值,定义了它们......当然:优先级。然而,有很多方法可以实现这样的 PQ。

      【讨论】:

        猜你喜欢
        • 2017-10-18
        • 2022-01-26
        • 2018-12-24
        • 1970-01-01
        • 2017-12-05
        • 2014-09-23
        • 2016-09-23
        • 2013-03-13
        • 2021-07-08
        相关资源
        最近更新 更多