原理
- 背景:常见的,用例已经有了N个元素,且有多个平行数组。只需要把索引加入队列。如果有现成的结构体数组,只要一个关于索引的优先队列即可。
- 注意到,只调整索引(一个整型数)要比交换结构体高效很多。
- 索引优先队列,可理解为能够快速访问最小元素的数组(甚至是任意一部分子集的最小元素,只把这一部分加入队列就好)。
API
函数名 |
功能 |
void insert(int k,KEY key) |
插入元素key,并和索引k关联 |
void change(int k,KEY key) |
将索引为k的值改为key |
void delMin() |
删除最小元素并返回索引 |
Key min() |
返回最小元素 |
void contains(int k) |
是否包含索引k |
实现
#pragma once
#include<string>
#include<iostream>
#include<vector>
using namespace std;#define out(x) cout<<x<<" "
#define hh cout<<endltemplate<class Key>
class IndexMinPQ
{
public:IndexMinPQ(int maxN);bool empty() {
return m_N == 0; }int size() {
return m_N; }bool contains(int k) {
return (*m_qp)[k] != -1; }int minIndex() {
return m_pq[1]; }Key keyOf(int k) {
return m_keys->at(k); }Key min();int delMin();void change(int k, Key key);void insert(int i, Key key);void remove(int k);
private:int m_maxN = 0;int m_N = 0;vector<int>* m_pq = nullptr;vector<int>* m_qp = nullptr;vector<Key>* m_keys = nullptr;void sink(int k);void swim(int k);bool less(int x, int y);void exch(int x, int y);bool greater(int i, int j);void validateIndex(int idx);
};void test_IndexMinPQ();
#include "IndexMinPQ.h"template<class Key>
inline IndexMinPQ<Key>::IndexMinPQ(int maxN)
{
if (maxN < 0) {
out("maxN needs >0.\n");return;}m_maxN = maxN;m_N = 0;m_keys = new vector<Key>(maxN + 1);m_pq = new vector<int>(maxN + 1);m_qp = new vector<int>(maxN + 1);for (int i = 1; i <= maxN; ++i){
m_qp->at(i) = -1;}}template<class Key>
void IndexMinPQ<Key>::insert(int i, Key key)
{
if (contains(i)) {
out("index is already in the priority queue.");return;}m_N++;m_qp->at(i) = m_N;m_pq->at(m_N) = i;m_keys->at(i) = key;swim(m_N);
}template<class Key>
Key IndexMinPQ<Key>::min()
{
int min_i = m_pq->at(1);return m_keys->at(min_i);
}template<class Key>
int IndexMinPQ<Key>::delMin()
{
if (m_N == 0) {
out("priority queue underflow.");return -1;}int min = m_pq->at(1);exch(1, m_N--);sink(1);m_qp->at(min) = -1;m_keys->at(min) = Key();m_pq->at(m_N + 1) = -1;return min;
}template<class Key>
void IndexMinPQ<Key>::change(int i, Key key)
{
validateIndex(i);if (!contains(i)) {
out("index is not in priority queue.");return;}m_keys->at(i) = key;swim(m_qp->at(i));sink(m_qp->at(i));
}template<class Key>
void IndexMinPQ<Key>::sink(int k)
{
while (k * 2 <= m_N) {
int j = 2 * k;if (j < m_N && less(j, j + 1)) j++;if (!less(k, j)) break;exch(k, j);k = j;}
}template<class Key>
void IndexMinPQ<Key>::swim(int k)
{
while (k > 1 && less(k / 2, k)) {
exch(k, k / 2);k = k / 2;}
}template<class Key>
void IndexMinPQ<Key>::exch(int x, int y)
{
Key swap_ = m_pq->at(x);m_pq->at(x) = m_pq->at(y);m_pq->at(y) = swap_;m_qp->at(m_pq->at(x)) = x;m_qp->at(m_pq->at(y)) = y;
}template<class Key>
bool IndexMinPQ<Key>::greater(int i, int j)
{
i = m_pq->at(i);j = m_pq->at(j);return m_keys->at(i) < m_keys->at(j);
}template<class Key>
bool IndexMinPQ<Key>::less(int x, int y)
{
x = m_pq->at(x);y = m_pq->at(y);return m_keys->at(x) > m_keys->at(y);
}template<class Key>
void IndexMinPQ<Key>::validateIndex(int idx)
{
if (idx<1 || idx>m_maxN) {
out("index error!\n");}
}void test_IndexMinPQ()
{
double a[4] = {
3.17,10.5,4.67,9.09 };IndexMinPQ<double> minPQ(9);for (int i = 0; i < 4; ++i) {
minPQ.insert(i + 1, a[i]);}out(minPQ.min()), hh;minPQ.change(3, 2.09);out(minPQ.min()), hh;minPQ.change(4, 1.89);out(minPQ.min()), hh;}int main() {
test_IndexMinPQ();system("pause");return 0;
}