C++ 在最小堆中查找最大元素

C++ 在最小堆中查找最大元素,c++,algorithm,optimization,stl,heap,C++,Algorithm,Optimization,Stl,Heap,我有一个最小堆: std::vector<int> h; ... std::make_heap(h.begin(), h.end(), std::greater<int>()); 但是,这必须扫描所有堆元素 标准库是否提供了在最小堆中查找最大元素的更有效算法?TL;在最小堆中,最大元素在叶节点中。因此,您可以将搜索限制在堆中大约一半的元素上,也就是说,将最大元素的搜索限制在叶节点上: auto max_it = std::max_element(first_leaf_i

我有一个最小堆:

std::vector<int> h;
...
std::make_heap(h.begin(), h.end(), std::greater<int>());
但是,这必须扫描所有堆元素

标准库是否提供了在最小堆中查找最大元素的更有效算法?

TL;在最小堆中,最大元素在叶节点中。因此,您可以将搜索限制在堆中大约一半的元素上,也就是说,将最大元素的搜索限制在叶节点上:

auto max_it = std::max_element(first_leaf_it, h.end());
请注意,这仍然需要线性时间,但常数因子比扫描所有元素要低,大约一半

下面是一个类似STL的算法实现,用于在迭代器对提供的最小堆中查找最大元素:

template<typename RandomIt>
auto min_heap_max_element(RandomIt first, RandomIt last) {
   auto n = last - first;

   if (n < 2)
      return first;

   auto first_leaf_it = first + (n - 2) / 2 + 1;
   return std::max_element(first_leaf_it, last);
}
如何查找堆中的第一个叶节点 堆的最后一个元素——h.end指出的元素——显然是一个叶节点,它的父节点是最后一个非叶节点,因为如果在这个元素后面有一个非叶节点,那么我们假设为堆的最后一个元素的元素就不会是最后一个元素,这是一个矛盾

因此,第一个叶节点将是紧跟在最后一个节点的父节点之后的元素

您可以很容易地找到最后一个节点的父节点在哪里:给定堆元素的索引i,它的父节点在索引i-1/2处。最后一个非叶节点的索引是h.size-2/2,因此第一个叶节点的索引是h.size-2/2+1


让我们假设最小堆中的最大元素位于非叶节点中。这意味着它至少有一个子节点。由于,此子节点必须大于或等于其父节点。如果子节点大于其父节点(即最大元素),则子节点大于最大值。这是不可能的,因为我们有一个矛盾。因此,它的所有子节点也必须是最大值,对于这些子节点也是如此。因此,如果最大值在堆中重复,或者只有最大值必须对应于叶节点,则在叶节点中有一个最大值。

< P>如果你确实需要更好的,即子线性时间复杂度,那么考虑使用A。此树中的任何节点都遵守以下属性:

如果某个值处于偶数级别,则该值在其后代中是最大的。 如果某个值位于奇数级别,则该值在其后代中最小

因此,根的值最小,其两个子项中的一个子项的值最大

插入/提取操作的时间复杂性与最小堆相同


检查相关的和可能重复的内容,非常感谢您的解释!:-谢谢你,我不知道最小最大堆。
template<typename RandomIt>
auto min_heap_max_element(RandomIt first, RandomIt last) {
   auto n = last - first;

   if (n < 2)
      return first;

   auto first_leaf_it = first + (n - 2) / 2 + 1;
   return std::max_element(first_leaf_it, last);
}
auto max_it = min_heap_max_element(h.begin(), h.end());