双端堆堆是一种双端优先队列,用完全二叉树的二叉堆结构同时存放最小堆和最大堆,该数据结构的详细介绍见
数据结构(C语言版) Ellis Horowitz Sartaj Sahni Susan Anderson-Freed 著 李建中 张岩 李治军译
机械工业出版社 p279-p283
这里仅给出C++实现
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
#include <random>
#include <ctime>
#include <deque>
using namespace std;
template <typename T>
class DoubleEndHeap //T只提供小于,其余用运算符重载
{
public:
bool isEmpty() { return _heap.size() == 1; }
size_t getSize() { return _heap.size(); }
T& _at(size_t index)
{
if (index >= _heap.size())
return NULLVALUE;
return _heap[index];
}
void insert(const T& key);
bool removeMinValue(T& key);
bool removeMaxValue(T& key);
bool isDoubleEndHeap();
bool changeValue(const T& value, size_t index);
bool Delete(size_t index);
DoubleEndHeap(const vector<T>& input, const T& Max_v, const T &Min_v);
DoubleEndHeap(const T& N) :NULLVALUE(N)
{
_heap.push_back(N);
}
private:
T NULLVALUE;
T Max_Value;
T Min_Value;
size_t max_node_for_min(size_t u);
size_t min_node_for_max(size_t u);
bool inMaxHeap(size_t u);
void siftUpInMinHeap(size_t start, const set<size_t>& root);
void siftUpInMaxHeap(size_t start, const set<size_t>& root);
void compareAndAdjust(size_t left_in_min_heap, size_t right_in_max_heap);
void adjustLeafAndFather(bool start_is_even, size_t leaf_start, size_t leaf_end, size_t father_start);
size_t siftDownInMinHeap(size_t start);
size_t siftDownInMaxHeap(size_t start);
void processPairSubHeap(size_t left, size_t right, size_t length);
bool isMinHeap(size_t u);
bool isMaxHeap(size_t u);
void process(size_t L, size_t R);
vector<T> _heap;
};
template <typename T>
void DoubleEndHeap<T>::process(size_t L, size_t R)
{
if (L << 1 > _heap.size())
{
if (R << 1 <= _heap.size())
{
if (_heap[(R << 1) - 1] > _heap[L - 1])
{
swap(_heap[(R << 1) - 1], _heap[L - 1]);
}
if ((R << 1) + 1 <= _heap.size())
{
if (_heap[R << 1] > _heap[L - 1])
{
swap(_heap[R << 1], _heap[L - 1]);
}
}
}
}
}
template <typename T>
bool DoubleEndHeap<T>::Delete(size_t index)
{
if (index == 0 || index >= _heap.size())
{
cout << "Error,invaild index" << endl;
return false;
}
if (inMaxHeap(index))
{
changeValue(Max_Value, index);
removeMaxValue(Max_Value);
}
else
{
changeValue(Min_Value, index);
removeMinValue(Min_Value);
}
return true;
}
template <typename T>
bool DoubleEndHeap<T>::changeValue(const T& value, size_t index) //index是数组下标
{
if (value < Min_Value || value > Max_Value)
{
cout << "Error,invaild value" << endl;
return false;
}
if (index == 0 || index >= _heap.size())
{
cout << "Error,invaild index" << endl;
return false;
}
if (_heap[index] == value)
return true;
if (inMaxHeap(index))
{
if (_heap[index] > value)
{
_heap[index] = value;
size_t down_point_in_max_heap = siftDownInMaxHeap(index + 1);
size_t corr_point_in_min_heap = min_node_for_max(down_point_in_max_heap - 1) + 1;
if (_heap[corr_point_in_min_heap - 1] > _heap[down_point_in_max_heap - 1])
{
swap(_heap[corr_point_in_min_heap - 1], _heap[down_point_in_max_heap - 1]);
set<size_t> _set({ 2 });
siftUpInMinHeap(corr_point_in_min_heap, _set);
}
process(down_point_in_max_heap, corr_point_in_min_heap);
}
else
{
_heap[index] = value;
set<size_t> _set({ 3 });
siftUpInMaxHeap(index + 1, _set);
}
}
else
{
if (_heap[index] < value)
{
_heap[index] = value;
size_t down_point_in_min_heap = siftDownInMinHeap(index + 1);
size_t corr_point_in_max_heap = max_node_for_min(down_point_in_min_heap - 1) + 1;
bool flag = false;
if (_heap[corr_point_in_max_heap - 1] < _heap[down_point_in_min_heap - 1])
{
swap(_heap[corr_point_in_max_heap - 1], _heap[down_point_in_min_heap - 1]);
flag = true;
}
process(corr_point_in_max_heap, down_point_in_min_heap);
if (flag)
{
set<size_t> _set;
_set.insert(3);
siftUpInMaxHeap(corr_point_in_max_heap, _set);
}
}
else
{
_heap[index] = value;
set<size_t> _set{2};
siftUpInMinHeap(index + 1, _set);
}
}
return true;
}
template <typename T>
DoubleEndHeap<T>::DoubleEndHeap(const vector<T>& input, const T& Max_v, const T& Min_v):_heap(1), Max_Value(Max_v), Min_Value(Min_v)
{
for (auto run = input.cbegin(); run != input.cend(); ++run)
{
if (*run < Min_Value || *run > Max_Value)
{
cout << "Error,invaild value" << endl;
exit(-1);
}
}
_heap.insert(_heap.end(), input.begin(), input.end());
if (_heap.size() <= 2)
return;
size_t left_most = 2, k = 1;
while ((left_most << 1) <= _heap.size())
{
left_most <<= 1;
++k;
}
size_t lowest_layer_node_num = 1ULL << k;
size_t lowest_layer_node_min_in_heap = _heap.size() - left_most + 1;
size_t mid;
if (lowest_layer_node_min_in_heap <= (lowest_layer_node_num >> 1) || lowest_layer_node_min_in_heap != lowest_layer_node_num)
{
if (lowest_layer_node_min_in_heap <= (lowest_layer_node_num >>= 1))
{
adjustLeafAndFather(false, left_most, _heap.size(), left_most - (lowest_layer_node_num >> 1));
}
else
{
processPairSubHeap(left_most, left_most + lowest_layer_node_num, lowest_layer_node_min_in_heap - lowest_layer_node_num);
if (_heap.size() % 2 == 0)
adjustLeafAndFather(true, left_most + lowest_layer_node_min_in_heap - lowest_layer_node_num, left_most + lowest_layer_node_num - 1, _heap.size() >> 1);
else
adjustLeafAndFather(false, left_most + lowest_layer_node_min_in_heap - lowest_layer_node_num, left_most + lowest_layer_node_num - 1, (_heap.size() >> 1) + 1);
}
left_most >>= 1;
}
lowest_layer_node_num >>= 1;
mid = left_most + lowest_layer_node_num;
while (left_most != mid)
{
processPairSubHeap(left_most, mid, lowest_layer_node_num);
left_most >>= 1;
mid >>= 1;
lowest_layer_node_num >>= 1;
}
}
template <typename T>
void DoubleEndHeap<T>::processPairSubHeap(size_t left, size_t right, size_t length)
{
for (size_t length_run = 1; length_run <= length; ++length_run)
{
compareAndAdjust(left, right);
++left;
++right;
}
}
template <typename T>
void DoubleEndHeap<T>::compareAndAdjust(size_t left_in_min_heap, size_t right_in_max_heap)
{
{
size_t down_point_in_max_heap = siftDownInMaxHeap(right_in_max_heap);
size_t corr_point_in_min_heap = min_node_for_max(down_point_in_max_heap - 1) + 1;
if (_heap[corr_point_in_min_heap - 1] > _heap[down_point_in_max_heap - 1])
{
swap(_heap[corr_point_in_min_heap - 1], _heap[down_point_in_max_heap - 1]);
if (corr_point_in_min_heap != left_in_min_heap)
{
set<size_t> _set({ left_in_min_heap * 2, left_in_min_heap * 2 + 1 });
siftUpInMinHeap(corr_point_in_min_heap, _set);
}
}
process(down_point_in_max_heap, corr_point_in_min_heap);
}
size_t down_point_in_min_heap = siftDownInMinHeap(left_in_min_heap);
size_t corr_point_in_max_heap = max_node_for_min(down_point_in_min_heap - 1) + 1;
bool flag = false;
if (_heap[corr_point_in_max_heap - 1] < _heap[down_point_in_min_heap - 1])
{
swap(_heap[corr_point_in_max_heap - 1], _heap[down_point_in_min_heap - 1]);
flag = true;
}
process(corr_point_in_max_heap, down_point_in_min_heap);
if (flag)
{
set<size_t> _set;
_set.insert(right_in_max_heap);
siftUpInMaxHeap(corr_point_in_max_heap, _set);
}
}
template <typename T>
void DoubleEndHeap<T>::adjustLeafAndFather(bool start_is_even, size_t leaf_start, size_t leaf_end, size_t father_start)
{
bool is_even_pos = start_is_even;
for (size_t run = leaf_start; run <= leaf_end; ++run)
{
if (_heap[run - 1] > _heap[father_start - 1])
swap(_heap[run - 1], _heap[father_start - 1]);
if (is_even_pos)
{
is_even_pos = false;
++father_start;
}
else
{
is_even_pos = true;
}
}
}
template <typename T>
size_t DoubleEndHeap<T>::siftDownInMinHeap(size_t start)
{
size_t sub = 2 * start;
T temp = _heap[start - 1];
while (sub <= _heap.size())
{
if (sub < _heap.size() && _heap[sub - 1] > _heap[sub])
++sub;
if (temp <= _heap[sub - 1])
break;
_heap[start - 1] = _heap[sub - 1];
start = sub;
sub *= 2;
}
_heap[start - 1] = temp;
return start;
}
template <typename T>
void DoubleEndHeap<T>::siftUpInMaxHeap(size_t start, const set<size_t> &root)
{
T temp = _heap[start - 1];
size_t father = start / 2;
while (root.find(start) == root.end())
{
if (temp <= _heap[father - 1])
break;
_heap[start - 1] = _heap[father - 1];
start = father;
father /= 2;
}
_heap[start - 1] = temp;
}
template <typename T>
size_t DoubleEndHeap<T>::siftDownInMaxHeap(size_t start)
{
size_t sub = 2 * start;
T temp = _heap[start - 1];
while (sub <= _heap.size())
{
if (sub < _heap.size() && _heap[sub - 1] < _heap[sub])
++sub;
if (temp >= _heap[sub - 1])
break;
_heap[start - 1] = _heap[sub - 1];
start = sub;
sub *= 2;
}
_heap[start - 1] = temp; //针对具体情况,该操作不应立即执行
return start;
}
template <typename T>
void DoubleEndHeap<T>::siftUpInMinHeap(size_t start, const set<size_t>& root)
{
T temp = _heap[start - 1];
size_t father = start / 2;
while (root.find(start) == root.end())
{
if (temp >= _heap[father - 1])
break;
_heap[start - 1] = _heap[father - 1];
start = father;
father /= 2;
}
_heap[start - 1] = temp;
}
template <typename T>
bool DoubleEndHeap<T>::isDoubleEndHeap()
{
if (_heap.size() <= 2)
return true;
if (isMinHeap(1) == false)
{
cout << "左子堆不是最小堆!" << endl;
return false;
}
if (isMaxHeap(2) == false)
{
cout << "右子堆不是最大堆!" << endl;
return false;
}
deque<size_t> work_queue_left;
work_queue_left.push_back(1);
deque<size_t> work_queue_right;
work_queue_right.push_back(2);
while (work_queue_left.empty() == false)
{
size_t cur = work_queue_left.front();
if (work_queue_right.empty() == false)
{
size_t right = work_queue_right.front();
work_queue_right.pop_front();
if (_heap[cur] > _heap[right])
{
cout << "左子堆节点" << cur + 1 << "关键码不小于等于右子堆对应节点" << right + 1 << "的关键码" << endl;
return false;
}
if (2 * (right + 1) <= _heap.size())
{
work_queue_right.push_back(2 * right + 1);
if (2 * (right + 1) + 1 <= _heap.size())
{
work_queue_right.push_back(2 * (right + 1));
}
}
}
else
{
break;
}
work_queue_left.pop_front();
if (2 * (cur + 1) <= _heap.size())
{
work_queue_left.push_back(2*cur + 1);
if (2 * (cur + 1) + 1 <= _heap.size())
{
work_queue_left.push_back(2 * (cur + 1));
}
}
}
if (work_queue_left.empty())
{
return true;
}
size_t parent = max_node_for_min(work_queue_left.front()) + 1;
parent -= 1;
bool left_child;
if (((work_queue_left.front() + 1) & 1) == 0)
{
left_child = true;
}
else
{
left_child = false;
}
while (work_queue_left.empty() == false)
{
size_t n = work_queue_left.front();
work_queue_left.pop_front();
if (_heap[n] > _heap[parent])
{
cout << "左子堆节点" << n + 1 << "关键码不小于等于右子堆对应节点" << parent + 1 << "的关键码" << endl;
return false;
}
if (left_child == false)
{
left_child = true;
++parent;
}
else
{
left_child = false;
}
}
return true;
}
template <typename T>
bool DoubleEndHeap<T>::isMaxHeap(size_t u)
{
size_t cur = u + 1;
if (2 * cur > _heap.size())
{
return true;
}
if (_heap[u] >= _heap[2 * cur - 1])
{
if (isMaxHeap(2 * cur - 1))
{
if (2 * cur + 1 <= _heap.size())
{
if (_heap[u] >= _heap[2 * cur])
{
if (isMaxHeap(2 * cur))
{
return true;
}
else
{
return false;
}
}
else
{
cout << "节点" << cur << "关键码不大于等于子女节点关键码" << endl;
return false;
}
}
else
{
return true;
}
}
else
{
return false;
}
}
else
{
cout << "节点" << cur << "关键码不大于等于子女节点关键码" << endl;
return false;
}
}
template <typename T>
bool DoubleEndHeap<T>::isMinHeap(size_t u)
{
size_t cur = u + 1;
if (2 * cur > _heap.size())
{
return true;
}
if (_heap[u] <= _heap[2 * cur - 1])
{
if (isMinHeap(2 * cur - 1))
{
if (2 * cur + 1 <= _heap.size())
{
if (_heap[u] <= _heap[2 * cur])
{
if (isMinHeap(2 * cur))
{
return true;
}
else
{
return false;
}
}
else
{
cout << "节点" << cur << "关键码不小于等于子女节点关键码" << endl;
return false;
}
}
else
{
return true;
}
}
else
{
return false;
}
}
else
{
cout << "节点" << cur << "关键码不小于等于子女节点关键码" << endl;
return false;
}
}
template <typename T>
bool DoubleEndHeap<T>::removeMaxValue(T& key)
{
if (_heap.size() == 1)
return false;
if (_heap.size() == 2)
{
key = _heap[1];
_heap.pop_back();
return true;
}
key = _heap[2];
size_t cur = 3;
size_t temp = 2 * cur;
T value = _heap.back();
_heap.pop_back();
while (temp <= _heap.size())
{
if (temp < _heap.size() && _heap[temp - 1] < _heap[temp])
{
++temp;
}
_heap[cur - 1] = _heap[temp - 1];
cur = temp;
temp *= 2;
}
_heap[cur - 1] = value;
size_t max_cor_key_index = min_node_for_max(cur - 1);
if ((max_cor_key_index + 1) * 2 <= _heap.size())
{
max_cor_key_index = 2 * max_cor_key_index + 1;
if (max_cor_key_index + 2 <= _heap.size() && _heap[max_cor_key_index + 1] > _heap[max_cor_key_index])
{
max_cor_key_index = max_cor_key_index + 1;
}
}
if (value >= _heap[max_cor_key_index])
{
set<size_t> _set{ 3 };
siftUpInMaxHeap(cur, _set);
}
else
{
swap(_heap[cur - 1], _heap[max_cor_key_index]);
set<size_t> _set{ 2 };
siftUpInMinHeap(max_cor_key_index + 1, _set);
}
return true;
}
template <typename T>
bool DoubleEndHeap<T>::removeMinValue(T& key)
{
if (_heap.size() == 1)
return false;
key = _heap[1];
if (_heap.size() == 2)
{
_heap.pop_back();
return true;
}
size_t cur = 2;
size_t temp = 2 * cur;
T value = _heap.back();
_heap.pop_back();
while (temp <= _heap.size())
{
if (temp < _heap.size() && _heap[temp - 1] > _heap[temp])
{
++temp;
}
_heap[cur - 1] = _heap[temp - 1];
cur = temp;
temp *= 2;
}
_heap[cur - 1] = value;
if (_heap.size() <= 2)
{
return true;
}
size_t min_cor_key_index = max_node_for_min(cur - 1);
if (value <= _heap[min_cor_key_index])
{
set<size_t> _set{ 2 };
siftUpInMinHeap(cur, _set);
}
else
{
swap(_heap[cur - 1], _heap[min_cor_key_index]);
set<size_t> _set{ 3 };
siftUpInMaxHeap(min_cor_key_index + 1, _set);
}
return true;
}
template <typename T>
void DoubleEndHeap<T>::insert(const T& key)
{
if (key < Min_Value || key > Max_Value)
{
cout << "Error,invaild value" << endl;
return;
}
_heap.push_back(key);
if (_heap.size() > 2)
{
if (inMaxHeap(_heap.size() - 1))
{
size_t min_cor_key_index = min_node_for_max(_heap.size() - 1);
if (_heap[min_cor_key_index] <= _heap.back())
{
set<size_t> _set{ 3 };
siftUpInMaxHeap(_heap.size(), _set);
}
else
{
swap(_heap[min_cor_key_index], _heap.back());
set<size_t> _set{ 2 };
siftUpInMinHeap(min_cor_key_index + 1, _set);
}
}
else
{
size_t max_cor_key_index = max_node_for_min(_heap.size() - 1);
if (_heap[max_cor_key_index] >= _heap.back())
{
set<size_t> _set{ 2 };
siftUpInMinHeap(_heap.size(), _set);
}
else
{
swap(_heap[max_cor_key_index], _heap.back());
set<size_t> _set{3};
siftUpInMaxHeap(max_cor_key_index + 1, _set);
}
}
}
}
template <typename T>
size_t DoubleEndHeap<T>::max_node_for_min(size_t u)
{
size_t _u = u + 1;
size_t k = 1;
while (k << 1 <= _u)
{
k <<= 1;
}
k >>= 1;
_u = _u + k;
if (_u > _heap.size())
{
return _u / 2 - 1;
}
return _u - 1;
}
template <typename T>
size_t DoubleEndHeap<T>::min_node_for_max(size_t u)
{
size_t _u = u + 1;
size_t k = 1;
while (k << 1 <= _u)
{
k <<= 1;
}
k >>= 1;
_u = _u - k;
return _u - 1;
}
template <typename T>
bool DoubleEndHeap<T>::inMaxHeap(size_t u)
{
size_t cur = u + 1;
while (true)
{
if (cur == 3)
{
return true;
}
if (cur == 2)
{
return false;
}
cur /= 2;
}
}
int main()
{
const int N = 10000;
vector<int> input(N);
for (int j = 0; j < N; ++j)
{
input[j] = j + 1;
}
shuffle(input.begin(), input.end(), default_random_engine());
DoubleEndHeap<int> obj(input, 200000, -200000);
for (;obj.isEmpty() == false;)
{
size_t j = rand() % (obj.getSize() - 1) + 1;
if (j == 1)
j = 2;
cout << "删除下标" << j << "元素" << endl;
obj.Delete(j - 1);
if (obj.isDoubleEndHeap())
{
cout << "双端堆性质维持" << endl;
}
else
{
cout << "双端堆性质破坏!" << endl;
exit(-1);
}
}
/*vector<int> input{16, 12, 12, 13, 14, 15};
DoubleEndHeap<int> obj(input);
if (obj.isDoubleEndHeap())
{
cout << "双端堆性质维持" << endl;
}
else
{
cout << "双端堆性质破坏!" << endl;
exit(-1);
}*/
/*for (int i = 1; i <= N; ++i)
{
vector<int> input(N);
for (int j = 0; j < i; ++j)
{
input[j] = j + 1;
}
shuffle(input.begin(), input.end(), default_random_engine(time(nullptr)));
DoubleEndHeap<int> obj(input);
if (obj.isDoubleEndHeap())
{
cout << "双端堆性质维持" << endl;
}
else
{
cout << "双端堆性质破坏!" << endl;
exit(-1);
}
}*/
for (const auto& run : input)
{
cout << "插入" << run << endl;
obj.insert(run);
if (obj.isDoubleEndHeap())
{
cout << "双端堆性质维持" << endl;
}
else
{
cout << "双端堆性质破坏" << endl;
exit(-1);
}
}
for (size_t i = 1; i <= N; ++i)
{
size_t j = rand() % (obj.getSize() - 1) + 1;
if (j == 1)
j = 2;
for (int run = -20; run <= 20; ++run)
{
cout << "将下标" << j << "元素" <<"增加" << run << endl;
obj.changeValue(obj._at(j - 1) + run, j - 1);
if (obj.isDoubleEndHeap())
{
cout << "增加后双端堆性质维持" << endl;
}
else
{
cout << "增加后双端堆性质破坏!" << endl;
exit(-1);
}
obj.changeValue(obj._at(j - 1) - run, j - 1);
if (obj.isDoubleEndHeap())
{
cout << "恢复后双端堆性质维持" << endl;
}
else
{
cout << "恢复后双端堆性质破坏!" << endl;
exit(-1);
}
}
}
/*while (obj.isEmpty() == false)
{
int key;
obj.removeMinValue(key);
cout << "移除最小值" << key << endl;
if (obj.isDoubleEndHeap())
{
cout << "双端堆性质维持" << endl;
}
else
{
cout << "双端堆性质破坏" << endl;
exit(-1);
}
}*/
/*while (obj.isEmpty() == false)
{
int key;
obj.removeMaxValue(key);
cout << "移除最大值" << key << endl;
if (obj.isDoubleEndHeap())
{
cout << "双端堆性质维持" << endl;
}
else
{
cout << "双端堆性质破坏" << endl;
exit(-1);
}
}*/
return 0;
}