C++ 自定义比较器未按预期工作的STL优先级队列

C++ 自定义比较器未按预期工作的STL优先级队列,c++,algorithm,stl,priority-queue,max-heap,C++,Algorithm,Stl,Priority Queue,Max Heap,我正在尝试使用自定义运算符实现优先级队列。该算法试图找到要执行的最小增量,以便阵列中没有两个相邻元素的绝对差值大于1 为此,我得到数组中的最大元素“x”,并将其相邻元素修改为x-1,然后对其他元素重复相同的操作 代码如下: #include<iostream> #include<algorithm> #include<vector> #include<queue> using namespace std; int arr[100], visite

我正在尝试使用自定义运算符实现优先级队列。该算法试图找到要执行的最小增量,以便阵列中没有两个相邻元素的绝对差值大于1
为此,我得到数组中的最大元素“x”,并将其相邻元素修改为x-1,然后对其他元素重复相同的操作
代码如下:

#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;

int arr[100], visited[100];
int sizeOfArray;
struct comp
{
public:
    bool operator() (int x1, int x2) {
    return arr[x1] < arr[x2];
    }
};  

int main(){
    cin>>sizeOfArray;
    priority_queue<int, vector<int>, comp> priorityQue;
    for(int i = 0; i < sizeOfArray; i++) {
        cin>>arr[i];
        priorityQue.push(i);
        visited[i]=0;
    }
    while(!priorityQue.empty()) {
        int index = priorityQue.top();
        priorityQue.pop();
        if(visited[index])   
            continue;
        visited[index]=1;

        cout<<"Currently at index: "<<index<<endl;

        int currentElement = arr[index];
        int dx[] = {-1, 1};    // left and right neighbours
        for(int k = 0; k < 2; k++) {
            int nextIndex = index + dx[k];
            if( nextIndex >= 0 && nextIndex < sizeOfArray && 
                (currentElement - arr[nextIndex]) > 1 ) 
            {
                arr[nextIndex] = currentElement - 1;
                cout<<"Modifying index :"<<nextIndex<<endl;
                cout<<"New Array is: ";
                // print array 
                for(int z=0;z<sizeOfArray;z++)
                    cout<<arr[z]<<" ";
                cout<<endl;
                
                priorityQue.push(nextIndex);
                cout<<"Pushing index "<<nextIndex<<" to queue"<<endl;
            }
        }
    }
    return 0;
}
#包括
#包括
#包括
#包括
使用名称空间std;
int arr[100],已访问[100];
int-sizeOfArray;
结构组件
{
公众:
布尔运算符()(整数x1,整数x2){
返回arr[x1]>sizeOfArray;
优先级队列优先级;
对于(int i=0;i>arr[i];
优先推(i);
访问[i]=0;
}
而(!priorityQue.empty()){
int index=priorityQue.top();
priorityQue.pop();
如果(已访问[索引])
继续;
访问量[索引]=1;

CUT

在将该项放入队列后仍然是该队列的一部分,您正在修改该项。优先级队列不支持该项,并产生未指定的结果。C++ STL不提供可更新优先级队列。

但是,看到您的用例,我怀疑这是竞争性算法编程。这个用例有不错的替代方案。我不推荐它们用于生产代码(至少没有适当的抽象)

第一个“合适”的替代方法是使用
std::set
。您的代码将非常相似,但有一些重要的区别:

  • 您不需要自定义比较器,而是依赖于对比较(您需要使用
    std::greater
    作为比较器,以使最大的项目“在顶部”
  • 您将把
    {a[index],index}
    作为此集合的元素
  • 您将使用
    .begin()
    而不是
    .top()
  • 在更新项目的值之前,您需要
    .erase()
    项目,并使用新值再次插入它们
我相信上面的操作与优先级队列的标准实现具有相同的复杂性。尽管更新看起来很慢,但我们只做了两个O(logn)操作——这与堆结构中的实际更新具有相同的复杂性

您可以使用示例中的间接比较器来实现它。一般来说,它可以工作,但您仍然需要擦除和插入循环更新。此外,您还需要比较比较器中的索引,以便使具有相同优先级的项不同,以便删除正确的项

此外,在许多常见情况下,我们还可以使用另一种技巧,如Dijkstra或Prim算法。在这些情况下,我们只将优先级更新为更高(较低的值)。在这种情况下,我们可以忽略擦除项,而只添加重复项。这是因为单个查询/更新的时间复杂性变为
O(logn^2)=O(2logn)=O(日志n)
。内存复杂性增加,但这通常不是问题

在最后一种情况下,您可以使用其他容器来满足您的偏好,无论是
std::priority\u queue
还是
std::multimap
都可以很好地工作。但在所有这些容器中,您都需要将优先级作为插入项的一部分,而不是通过间接比较器使用它

作为附录,这是您的代码,并对其进行了更改以按预期工作:

#包括
#包括
#包括
#包括
使用名称空间std;
int arr[100],已访问[100];
int-sizeOfArray;
int main(){
cin>>sizeOfArray;
优先级队列优先级;
对于(int i=0;i>arr[i];
priorityQue.push({arr[i],i});
访问[i]=0;
}
而(!priorityQue.empty()){
int index=priorityQue.top().second;
priorityQue.pop();
如果(已访问[索引])
继续;
访问量[索引]=1;

CUT<代码> TyPulf LoLunLL;——不需要这样的宏。C++有<代码> It64 64 t < /代码>——它精确地描述了类型。然后有这个<代码>包含了< /Cord>——包括适当的头文件,而不是这个头文件。不要使用逗号运算符来“链”。表达式转换为单个语句,请使用单独的语句。同时尽量避免使用全局变量和简短的非描述性名称。所有这些都会使代码更难阅读、理解、维护和调试。@有些程序员编辑了
,在这种情况下,我们可以忽略删除项,而只添加重复项。
这是正确的我所做的不是修改队列,而是添加重复的索引,其优先级由
comp
函数决定。但是您的比较器使用全局
arr[]
array。因此,当您第二次插入密钥时,您正在修改已经在其中的密钥的值-这会导致不可预测的行为。为了清楚地了解没有此问题的解决方案的外观,我添加了工作代码。我认为密钥的值不会更改。根据优先级队列,容器与我拥有的数组是分开的已定义。key的“value”是
arr[index]
的值。这是用于比较的值,该值会更改。我相信优先级队列是作为堆实现的。在第一个
pop()之后
优先级队列包含
1 1 0
。索引2的1很可能位于根目录中,而索引1和3位于根目录下。更新arr[1]时=3,并再次插入1。仅更新新元素的位置。它可能会附着在旧1的下方。但是,由于更新了旧1的值,新1永远不会在其上方,也不会根据2进行检查。在arr[1]=3之后,堆处于无效状态