C++ 自定义比较器未按预期工作的STL优先级队列
我正在尝试使用自定义运算符实现优先级队列。该算法试图找到要执行的最小增量,以便阵列中没有两个相邻元素的绝对差值大于1C++ 自定义比较器未按预期工作的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
为此,我得到数组中的最大元素“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之后,堆处于无效状态