C++ 使用C++;标准库
我有一个使用C++ 使用C++;标准库,c++,algorithm,data-structures,stl,heap,C++,Algorithm,Data Structures,Stl,Heap,我有一个使用std::make_heap的堆: std::vector<int> v{1,2,3,5,9,20,3}; std::make_heap(v.begin(), v.end()); std::vector<int> v{1,2,3,5,9,20,3}; // create a min heap std::make_heap(v.begin(), v.end(), std::greater<int>{}); // set 4th element t
std::make_heap
的堆:
std::vector<int> v{1,2,3,5,9,20,3};
std::make_heap(v.begin(), v.end());
std::vector<int> v{1,2,3,5,9,20,3};
// create a min heap
std::make_heap(v.begin(), v.end(), std::greater<int>{});
// set 4th element to 35 in O(log n)
set_heap_element(v.begin(), v.end(), v.begin() + 3, 35, std::greater<int>{});
// is the min-heap property satisfied?
assert(std::is_heap(v.begin(), v.end(), std::greater<int>{}));
在中的标准库中是否有方法在O(logn)
时间中再次调整堆,其中n
是容器的大小。基本上我在寻找heapify函数。我知道什么元素被改变了
我知道std::make_heap
是O(n log n)
time。我也经历了重复的问题,但这是不同的意义上,它是改变最大元素。对于这个问题,已经给出了O(logn)
复杂性的解决方案
我试图更改堆中的任何随机元素 我也一直面临着想要一个“可更新堆”的问题。然而,最后,我没有编写自定义的可更新堆或类似的代码,而是稍微改变了解决方法 为了在不需要显式遍历堆的情况下保持对最佳元素的访问,可以使用要排序的元素的版本包装器。每个唯一的true元素都有一个版本计数器,每当元素发生更改时,该计数器都会增加。然后,堆中的每个包装器都携带元素的一个版本,即创建包装器时的版本:
struct HeapElemWrapper
{
HeapElem * e;
size_t version;
double priority;
HeapElemWrapper(HeapElem * elem)
: e(elem), version(elem->currentVersion), priority(0.0)
{}
bool upToDate() const
{
return version == e->currentVersion;
}
// operator for ordering with heap / priority queue:
// smaller error -> higher priority
bool operator<(const HeapElemWrapper & other) const
{
return this->priority> other.priority;
}
};
struct-heaplemWrapper
{
HeapElem*e;
尺寸(t)版本;;
双重优先;
heaplemWrapper(heaplem*elem)
:e(元素),版本(元素->当前版本),优先级(0.0)
{}
bool update()常量
{
返回版本==e->currentVersion;
}
//用于使用堆/优先级队列排序的运算符:
//错误越小->优先级越高
布尔运算符优先级>其他.优先级;
}
};
当从堆中弹出最上面的元素时,您可以简单地检查这个包装器元素,看看它是否与原始元素是最新的。如果没有,只需处理它,然后弹出下一个。这种方法非常有效,我在其他应用程序中也看到过。您需要注意的唯一一件事是,您不时地(比如,每1000次插入左右)对堆进行一次遍历,以清除其中过时的元素。我也一直面临需要“可更新堆”的问题。然而,最后,我没有编写自定义的可更新堆或类似的代码,而是稍微改变了解决方法 为了在不需要显式遍历堆的情况下保持对最佳元素的访问,可以使用要排序的元素的版本包装器。每个唯一的true元素都有一个版本计数器,每当元素发生更改时,该计数器都会增加。然后,堆中的每个包装器都携带元素的一个版本,即创建包装器时的版本:
struct HeapElemWrapper
{
HeapElem * e;
size_t version;
double priority;
HeapElemWrapper(HeapElem * elem)
: e(elem), version(elem->currentVersion), priority(0.0)
{}
bool upToDate() const
{
return version == e->currentVersion;
}
// operator for ordering with heap / priority queue:
// smaller error -> higher priority
bool operator<(const HeapElemWrapper & other) const
{
return this->priority> other.priority;
}
};
struct-heaplemWrapper
{
HeapElem*e;
尺寸(t)版本;;
双重优先;
heaplemWrapper(heaplem*elem)
:e(元素),版本(元素->当前版本),优先级(0.0)
{}
bool update()常量
{
返回版本==e->currentVersion;
}
//用于使用堆/优先级队列排序的运算符:
//错误越小->优先级越高
布尔运算符优先级>其他.优先级;
}
};
当从堆中弹出最上面的元素时,您可以简单地检查这个包装器元素,看看它是否与原始元素是最新的。如果没有,只需处理它,然后弹出下一个。这种方法非常有效,我在其他应用程序中也看到过。您需要注意的唯一一件事是,您不时地(比如,每1000次插入左右)对堆进行一次遍历,以清除其中过时的元素。如果我们仔细看一下您的陈述: 现在,我通过更改堆的一个随机元素来扰乱堆 对于在
O(log n)
中进行重定位,您只能直接“干扰”向量的后面或前面(以某种方式对应于插入或删除元素)。在这些情况下,可以通过和算法实现(再)重映射,这需要对数运行时间
就是后面,
v.back() = 35;
std::push_heap(v.begin(), v.end()); // heapify in O(log n)
或正面:
v.front() = 35;
// places the front at the back
std::pop_heap(v.begin(), v.end()); // O(log n)
// v.back() is now 35, but it does not belong to the heap anymore
// make the back belong to the heap again
std::push_heap(v.begin(), v.end()); // O(log n)
否则,需要使用重新调整整个向量,这需要线性运行时间
总结
无法使用标准库(即函数模板
std::push_heap
和std::pop_heap
)修改堆的任意元素并在对数运行时间内实现堆化。但是,您始终可以自己实现堆的swim和sink操作,以便在对数运行时间内堆化。如果我们仔细看一下您的语句:
现在,我通过更改堆的一个随机元素来扰乱堆
对于在O(log n)
中进行重定位,您只能直接“干扰”向量的后面或前面(以某种方式对应于插入或删除元素)。在这些情况下,可以通过和算法实现(再)重映射,这需要对数运行时间
就是后面,
v.back() = 35;
std::push_heap(v.begin(), v.end()); // heapify in O(log n)
或正面:
v.front() = 35;
// places the front at the back
std::pop_heap(v.begin(), v.end()); // O(log n)
// v.back() is now 35, but it does not belong to the heap anymore
// make the back belong to the heap again
std::push_heap(v.begin(), v.end()); // O(log n)
否则,需要使用重新调整整个向量,这需要线性运行时间
总结
无法使用标准库(即函数模板
std::push_heap
和std::pop_heap
)修改堆的任意元素并在对数运行时间内实现堆化。但是,您始终可以自己实现堆的swim和sink操作,以便在对数运行时间内进行堆处理。您可以自己完成:
void modify_heap_element(std::vector<int> &heap, size_t index, int value)
{
//while value is too large for its position, bubble up
while(index > 0 && heap[(index-1)>>1] < value)
{
size_t parent = (index-1)>>1;
heap[index]=heap[parent];
index = parent;
}
//while value is too large for its position sift down
for (;;)
{
size_t left=index*2+1;
size_t right=left+1;
if (left >= heap.size())
break;
size_t bigchild = (right >= heap.size() || heap[right] < heap[left] ?
left : right );
if (!(value < heap[bigchild]))
break;
heap[index]=heap[bigchild];
index = bigchild;
}
heap[index] = value;
}
void modify_heap_元素(std::vector&heap,size\t index,int值)
{
//当价值对其位置而言太大时,泡沫就会出现
而(索引>0&&heap[(索引-1)>>1]>1;
堆[索引]=堆[父];
指数=父母;
}
//当值对于其位置太大时,请向下筛选
对于(;;)
{
assert(std::is_heap(v.begin(), v.end()));
std::vector<int> v{1,2,3,5,9,20,3};
// create a min heap
std::make_heap(v.begin(), v.end(), std::greater<int>{});
// set 4th element to 35 in O(log n)
set_heap_element(v.begin(), v.end(), v.begin() + 3, 35, std::greater<int>{});
// is the min-heap property satisfied?
assert(std::is_heap(v.begin(), v.end(), std::greater<int>{}));