heap

2021-06-21

Heap是一种先进先出的数据结构,当然经过了改进,后面有了双向的deque和极值在堆顶的特殊结构。这一篇主要讲的就是通用的queue,另外的dequepriority_queue可以进一步看看。

queue

queue:

  • init with list instead of default deque is fast. queue<int, list> is better.
  • Constructor like: queue que({1,2,3}); list/deque
  • operation:empty, size, front(non-const reference), back, push, pop.
  • Non-member: swap, swap two queue.

deque:

  • Constructor: deque(4, 5); 4 个 5;deque(iter.begin(), iter.end())
  • push_front, push_back, insert, pop_front, pop_back, emplace, emplace_front, emplace_back, front, back, begin, end, r(c)begin, clear, at(boundary check), [], resize, erase
  • Empty, size, swap, max_size, shrink_to_fit(an optimization skill), assign
  • Non-member: swap

priority_queue:

  • heap sort
  • Top(const reference), push, emplace, pop, empty, swap, size, swap
  • emplace 可以直接调用构造函数,直接传构造函数的参数即可。push先需要构造出对象,多了一次拷贝。
  • https://blog.csdn.net/Kprogram/article/details/82055673
  • Non-member: swap
  • 常用初始化方法:(默认最大堆,top是最大的元素)
class mycomparison
{
  bool reverse;
public:
  mycomparison(const bool& revparam=false)
    {reverse=revparam;}
  bool operator() (const int& lhs, const int&rhs) const
  {
    if (reverse) return (lhs>rhs);
    else return (lhs<rhs);
  }
};

int myints[]= {10,60,50,20};

std::priority_queue<int> first;
std::priority_queue<int> second (myints,myints+4);
std::priority_queue<int, std::vector<int>, std::greater<int> >
                          third (myints,myints+4);
// using mycomparison:
typedef std::priority_queue<int,std::vector<int>,mycomparison> mypq_type;

mypq_type fourth;                       // less-than comparison
mypq_type fifth (mycomparison(true));   // greater-than comparison

初始化的时候,如果是自定义的话,需要把这个自定义加上
std::priority_queue<mergeRecord, std::vector<mergeRecord>, mycomparison>
    recsHeap(std::begin(initialRecords), std::end(initialRecords), mycomparison(false,field));
// 621. Task Scheduler
// Method 1: mathematics 
int leastInterval(vector<char>& tasks, int n) {
  int frequency[26] = {0};
  for (const auto task : tasks) {
    ++frequency[task-'A'];
  }
  int max_frequency = 0;
  int max_num = 0;
  for (int i = 0; i < 26; ++i) {
    if (frequency[i] > max_frequency) {
      max_frequency = frequency[i];
      max_num = 1;
    } else if (frequency[i] == max_frequency) {
      ++max_num;
    }
  }
  
  return max(tasks.size(), static_cast<unsigned long>((max_frequency - 1) * (n + 1) + max_num));
}
// Method 2: priority_queue
int leastInterval(vector<char>& tasks, int n) {
  unordered_map<char, int> record;
  for (const auto task : tasks) {
    ++record[task];
  }
  priority_queue<int> status;
  for (const auto [name, frequency] : record) {
    status.push(frequency);
  }
  int ans = 0;
  while (!status.empty()) {
    vector<int> tmp;
    int count = 0;
    for (int i = 0; i <= n; ++i) {
      if (status.empty()) break;
      tmp.push_back(status.top());
      ++count;
      status.pop();
    }
    for (auto& t : tmp) {
      if (--t > 0) {
        status.push(t);
      }
    }
    ans += status.empty() ? count : n + 1;
  }
  return ans;
}


// 622. Design Circular Queue
class MyCircularQueue {
public:
int size_ = 0;
int front_idx_ = -1;
int rear_idx_ = -1;
vector<int> data_;
  
MyCircularQueue(int k) {
  size_ = k;        
  data_.resize(k);
}
    
bool enQueue(int value) {
  if (isFull()) return false;
  
  if (isEmpty()) {
    front_idx_ = rear_idx_ = 0;
  } else {
    ++rear_idx_;
    rear_idx_ %= size_;
  }
  data_[rear_idx_] = value;
  
  return true;
}
    
bool deQueue() {
  if (isEmpty()) return false;
  
  if (front_idx_ == rear_idx_) {
    front_idx_ = rear_idx_ = -1;
  } else {
    front_idx_ = ++front_idx_ % size_;
  }
  
  return true;
}
    
int Front() {
  return front_idx_ == -1? -1:data_[front_idx_];      
}
    
int Rear() {
  return rear_idx_ == -1 ? -1:data_[rear_idx_];      
}
    
bool isEmpty() {
  return front_idx_ < 0 && rear_idx_ < 0;      
}
    
bool isFull() {
  return (front_idx_ - rear_idx_ == 1) || ((rear_idx_ == size_ - 1) && (front_idx_ == 0));      
}
};

// 641. Design Circular Deque
class MyCircularDeque {
public:
  
int size_ = 0;
int count_ = 0;
int front_index_ = -1;
int rear_index_ = -1;  
vector<int> data_;  
  
/** Initialize your data structure here. Set the size of the deque to be k. */
MyCircularDeque(int k) {
  size_ = k;      
  data_.resize(k);
}
    
/** Adds an item at the front of Deque. Return true if the operation is successful. */
bool insertFront(int value) {
  if (isFull()) return false;
  if (isEmpty()) {
    front_index_ = rear_index_ = 0;
  }
  else {
    front_index_ = (front_index_ - 1 + size_) % size_;
  } 
  data_[front_index_] = value;
  ++count_;
  return true;
}
    
/** Adds an item at the rear of Deque. Return true if the operation is successful. */
bool insertLast(int value) {
  if (isFull()) return false;
  if (isEmpty()) {
    rear_index_ = front_index_ = 0; 
  } else {
    rear_index_ = (rear_index_ + 1) % size_;
  }  
  data_[rear_index_] = value;
  ++count_;
  return true;
}
    
/** Deletes an item from the front of Deque. Return true if the operation is successful. */
bool deleteFront() {
  if (isEmpty()) return false;
  front_index_ = (front_index_ + 1) % size_;
  --count_;
  return true;
}
    
/** Deletes an item from the rear of Deque. Return true if the operation is successful. */
bool deleteLast() {
  if (isEmpty()) return false;
  rear_index_ = (rear_index_ - 1 + size_) % size_;
  --count_;
  return true;
}
    
/** Get the front item from the deque. */
int getFront() {
  return isEmpty() ? -1: data_[front_index_];        
}
    
/** Get the last item from the deque. */
int getRear() {
  return isEmpty() ? -1: data_[rear_index_];
}
    
/** Checks whether the circular deque is empty or not. */
bool isEmpty() {
  return !count_;        
}
    
/** Checks whether the circular deque is full or not. */
bool isFull() {
  return count_ == size_;        
}
};

/**
 * Your MyCircularDeque object will be instantiated and called as such:
 * MyCircularDeque* obj = new MyCircularDeque(k);
 * bool param_1 = obj->insertFront(value);
 * bool param_2 = obj->insertLast(value);
 * bool param_3 = obj->deleteFront();
 * bool param_4 = obj->deleteLast();
 * int param_5 = obj->getFront();
 * int param_6 = obj->getRear();
 * bool param_7 = obj->isEmpty();
 * bool param_8 = obj->isFull();
 */

// 353. Design Snake Game
class SnakeGame {
public:
/** Initialize your data structure here.
    @param width - screen width
    @param height - screen height 
    @param food - A list of food positions
    E.g food = [[1,1], [1,0]] means the first food is positioned at [1,1], the second is at [1,0]. */
  
deque<pair<int, int>> snake_;
unordered_map<int, bool> record_;
  
int width_ = 0;
int height_ = 0;
int food_index_ = 0;
vector<vector<int>> food_;  

SnakeGame(int width, int height, vector<vector<int>>& food) {
  width_ = width;
  height_ = height;
  food_ = std::move(food);
  snake_.emplace_back(make_pair(0, 0));
}
    
/** Moves the snake.
    @param direction - 'U' = Up, 'L' = Left, 'R' = Right, 'D' = Down 
    @return The game's score after the move. Return -1 if game over. 
    Game over when snake crosses the screen boundary or bites its body. */
int move(string direction) {
  auto tp = snake_.front();
  
  if (direction == "U") {
    --tp.first;   
  } else if (direction == "D") {
    ++tp.first;
  } else if (direction == "L") {
    --tp.second;
  } else {
    ++tp.second;
  }
  
  if (tp.first < 0 || tp.first >= height_ ||
      tp.second < 0 || tp.second >= width_) {
    return -1;
  }
  
  snake_.emplace_front(tp);
  if (food_index_ < food_.size() && (tp.first == food_[food_index_][0]
      && tp.second == food_[food_index_][1])) {
    ++food_index_;
  } else {
    const auto tmp = snake_.back();
    record_[tmp.first * width_ + tmp.second] = false;
    snake_.pop_back();
    if (record_[tp.first * width_ + tp.second]) {
      return -1;
    }
  }
  record_[tp.first * width_ + tp.second] = true;
  
  return snake_.size() - 1;  
}

};

/**
 * Your SnakeGame object will be instantiated and called as such:
 * SnakeGame* obj = new SnakeGame(width, height, food);
 * int param_1 = obj->move(direction);
 */