Skip to content

leftist_heap.hpp

SECTIONData Structure INCLUDEnoya/leftist_heap.hpp

Meldable leftist heap with O(log n) push, pop, and heap merging.

提供可快速合并的优先队列;题目频繁合并两堆元素并取出极值时使用。

Implementation

View on GitHub

#ifndef NOYA_LEFTIST_HEAP_HPP
#define NOYA_LEFTIST_HEAP_HPP 1

/// @complexity Time: O(log n) push/pop/meld.
/// Space: O(n) nodes and O(log n) stack.

#include <cassert>
#include <functional>
#include <utility>

namespace noya {

/// @brief Meldable leftist heap with O(log n) push, pop, and heap merging.
template <class T, class Compare = std::less<T>> struct leftist_heap {
  struct node {
    T value;
    node *left = nullptr;
    node *right = nullptr;
    int rank = 1;
  };

  node *root = nullptr;
  Compare compare{};

  leftist_heap() = default;
  leftist_heap(const leftist_heap &) = delete;
  leftist_heap &operator=(const leftist_heap &) = delete;
  leftist_heap(leftist_heap &&other) noexcept
      : root(std::exchange(other.root, nullptr)),
        compare(std::move(other.compare)) {}
  leftist_heap &operator=(leftist_heap &&other) noexcept {
    if (this != &other) {
      clear(root);
      root = std::exchange(other.root, nullptr);
      compare = std::move(other.compare);
    }
    return *this;
  }
  ~leftist_heap() { clear(root); }

  bool empty() const { return root == nullptr; }
  const T &top() const {
    assert(root != nullptr);
    return root->value;
  }
  void push(const T &value) { root = meld(root, new node{value}); }
  void push(T &&value) { root = meld(root, new node{std::move(value)}); }
  void pop() {
    assert(root != nullptr);
    node *old = root;
    root = meld(root->left, root->right);
    delete old;
  }
  void merge(leftist_heap &other) {
    if (this != &other) {
      root = meld(root, std::exchange(other.root, nullptr));
    }
  }

private:
  int rank(node *current) const {
    return current == nullptr ? 0 : current->rank;
  }
  node *meld(node *first, node *second) {
    if (first == nullptr || second == nullptr) {
      return first == nullptr ? second : first;
    }
    if (compare(second->value, first->value)) {
      std::swap(first, second);
    }
    first->right = meld(first->right, second);
    if (rank(first->left) < rank(first->right)) {
      std::swap(first->left, first->right);
    }
    first->rank = rank(first->right) + 1;
    return first;
  }
  void clear(node *current) {
    if (current != nullptr) {
      clear(current->left);
      clear(current->right);
      delete current;
    }
  }
};

} // namespace noya

#endif // NOYA_LEFTIST_HEAP_HPP
#include <cassert>
#include <functional>
#include <utility>

/// @complexity Time: O(log n) push/pop/meld.
/// Space: O(n) nodes and O(log n) stack.

namespace noya {

/// @brief Meldable leftist heap with O(log n) push, pop, and heap merging.
template <class T, class Compare = std::less<T>> struct leftist_heap {
  struct node {
    T value;
    node *left = nullptr;
    node *right = nullptr;
    int rank = 1;
  };

  node *root = nullptr;
  Compare compare{};

  leftist_heap() = default;
  leftist_heap(const leftist_heap &) = delete;
  leftist_heap &operator=(const leftist_heap &) = delete;
  leftist_heap(leftist_heap &&other) noexcept
      : root(std::exchange(other.root, nullptr)),
        compare(std::move(other.compare)) {}
  leftist_heap &operator=(leftist_heap &&other) noexcept {
    if (this != &other) {
      clear(root);
      root = std::exchange(other.root, nullptr);
      compare = std::move(other.compare);
    }
    return *this;
  }
  ~leftist_heap() { clear(root); }

  bool empty() const { return root == nullptr; }
  const T &top() const {
    assert(root != nullptr);
    return root->value;
  }
  void push(const T &value) { root = meld(root, new node{value}); }
  void push(T &&value) { root = meld(root, new node{std::move(value)}); }
  void pop() {
    assert(root != nullptr);
    node *old = root;
    root = meld(root->left, root->right);
    delete old;
  }
  void merge(leftist_heap &other) {
    if (this != &other) {
      root = meld(root, std::exchange(other.root, nullptr));
    }
  }

private:
  int rank(node *current) const {
    return current == nullptr ? 0 : current->rank;
  }
  node *meld(node *first, node *second) {
    if (first == nullptr || second == nullptr) {
      return first == nullptr ? second : first;
    }
    if (compare(second->value, first->value)) {
      std::swap(first, second);
    }
    first->right = meld(first->right, second);
    if (rank(first->left) < rank(first->right)) {
      std::swap(first->left, first->right);
    }
    first->rank = rank(first->right) + 1;
    return first;
  }
  void clear(node *current) {
    if (current != nullptr) {
      clear(current->left);
      clear(current->right);
      delete current;
    }
  }
};

} // namespace noya