C++的STL提供了make_heap、push_heap、pop_heap、sort_heap等算法,它们用来将一个随机存储的数组或者容器等转换为一个heap。这里所说的转换为heap意思是将原来的存储顺序改变,将转换成的堆层序遍历后所得到的元素顺序作为数组或者容器新的元素顺序(实质上就是对原来的数据用一个算法换了一下元素顺序)。
1、make_heap()
函数声明:
template <class RandomAccessIterator>
void make_heap(RandomAccessIterator first, RandomAccessIterator last);
template <class RandomAccessIterator, class Compare>
void make_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
make_heap的功能是将一段现有的数据转化成一个堆,默认情况下生成的是一个大堆。
在第一种声明中,参数为迭代器类型,当我们传入一个左闭右开的区间[first, last)时,它会自动把这个区间的数据转化成一个大堆。
在第二种声明中,多了一个模板参数,用于我们给他传入一个比较类型,用这个比较类型来实现小堆的转化。当我们想实现小堆转化时,首先要#include <functional>
,然后参数中使用great<int>()
,需要注意的是当make_heap中使用了greater()后,后面pop_heap、push_heap和sort_heap都需要加上greater()。
生成大堆的代码:
#include <iostream>
#include <vector>
#include <functional>
int main()
{
vector<int> v = { 5, 7, 9, 30, 4, 1, 0, 2 };
for (const auto &e : v)
cout << e << " ";
cout << endl;
//生成一个大堆
make_heap(v.begin(), v.end());
for (const auto &e : v)
cout << e << " ";
cout << endl;
return 0;
}
输出结果:
生成小堆的代码:
#include <iostream>
#include <vector>
#include <functional>
int main()
{
vector<int> v = { 5, 7, 9, 30, 4, 1, 0, 2 };
for (const auto &e : v)
cout << e << " ";
cout << endl;
//生成一个小堆
make_heap(v.begin(), v.end(), greater<int>());
for (const auto &e : v)
cout << e << " ";
cout << endl;
return 0;
}
输出结果:
2、push_heap
函数声明:
template <class RandomAccessIterator>
void push_heap(RandomAccessIterator first, RandomAccessIterator last);
template <class RandomAccessIterator, class Compare>
void push_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
push_heap的功能是往堆中插入一个数据。但是,它的默认前提是区间[first, last - 2]已经满足堆结构,并且要插入的数据已经插入到区间的最后一个位置。因为STL库提供的push_heap算法没有插入元素,仅仅是完成插入元素后的调整工作,将插入元素后的区间恢复成堆结构。我们需要注意,当一次性插入多个数据然后再调用push_heap进行调整的时候,除最后插入的数据之外的其他前面插入的数据必须保证和已有数据依然能够构成堆结构,因为push_heap只是对左闭右开区间的最后一个数据进行调整,并且认为前面的数据已经满足堆结构,所以如何前面插入的数据不能保证堆结构的话就会报错。
对大堆的操作:
#include <iostream>
#include <vector>
#include <functional>
int main()
{
vector<int> v = { 5, 7, 9, 30, 4, 1, 0, 2 };
for (const auto &e : v)
cout << e << " ";
cout << endl;
//生成一个大堆
make_heap(v.begin(), v.end());
for (const auto &e : v)
cout << e << " ";
cout << endl;
//先尾插一个元素
v.push_back(70);
//再进行调整
push_heap(v.begin(), v.end());
for (const auto &e : v)
cout << e << " ";
cout << endl;
return 0;
}
输出结果:
对小堆的操作:
#include <iostream>
#include <vector>
#include <functional>
int main()
{
vector<int> v = { 5, 7, 9, 30, 4, 1, 0, 2 };
for (const auto &e : v)
cout << e << " ";
cout << endl;
//生成一个小堆
make_heap(v.begin(), v.end(), greater<int>());
for (const auto &e : v)
cout << e << " ";
cout << endl;
//先尾插一个元素
v.push_back(70);
//再进行调整
push_heap(v.begin(), v.end(), greater<int>());
for (const auto &e : v)
cout << e << " ";
cout << endl;
return 0;
}
输出结果:
3、pop_heap
函数声明:
template <class RandomAccessIterator>
void pop_heap(RandomAccessIterator first, RandomAccessIterator last);
template <class RandomAccessIterator, class Compare>
void pop_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
pop_heap的功能也是实现调整工作,但是是删除前的调整。pop_head会将堆顶的元素与最后一个元素(注意最后一个元素是last的上一个元素)交换,然后再调整,将除了最后一个元素的剩余其他元素重新恢复成堆结构。需要注意的是每次pop一个元素后,下一次pop时就需要将区间缩小1(last减1)。
对大堆的操作:
#include <iostream>
#include <vector>
#include <functional>
int main()
{
vector<int> v = { 5, 7, 9, 30, 4, 1, 0, 2 };
for (const auto &e : v)
cout << e << " ";
cout << endl;
//生成一个大堆
make_heap(v.begin(), v.end());
for (const auto &e : v)
cout << e << " ";
cout << endl;
//多次pop_heap实现排序的效果
for (int i = 0; i < v.size(); ++i)
pop_heap(v.begin(), v.end() - i);
for (const auto &e : v)
cout << e << " ";
cout << endl;
}
return 0;
}
输出结果:
对小堆的操作:
#include <iostream>
#include <vector>
#include <functional>
int main()
{
vector<int> v = { 5, 7, 9, 30, 4, 1, 0, 2 };
for (const auto &e : v)
cout << e << " ";
cout << endl;
//生成一个小堆
make_heap(v.begin(), v.end(), greater<int>());
for (const auto &e : v)
cout << e << " ";
cout << endl;
for (int i = 0; i < v.size(); ++i)
pop_heap(v.begin(), v.end() - i, greater<int>());
for (const auto &e : v)
cout << e << " ";
cout << endl;
return 0;
}
输出结果:
4、sort_heap
函数声明:
template <class RandomAccessIterator>
void sort_heap(RandomAccessIterator first, RandomAccessIterator last);
template <class RandomAccessIterator, class Compare>
void sort_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
sort_heap的功能就相当于多次调用heap_pop,我们每次调用heap_pop都将栈顶元素与最后元素进行交换(将栈中最大元素与栈中最后一个元素交换),然后last减1,重复调用heap_pop一直到只剩下1个元素,我们就实现了将元素排序。
对大堆的操作:
#include <iostream>
#include <vector>
#include <functional>
int main()
{
vector<int> v = { 5, 7, 9, 30, 4, 1, 0, 2 };
for (const auto &e : v)
cout << e << " ";
cout << endl;
//生成一个大堆
make_heap(v.begin(), v.end());
for (const auto &e : v)
cout << e << " ";
cout << endl;
sort_heap(v.begin(), v.end());
for (const auto &e : v)
cout << e << " ";
cout << endl;
}
return 0;
}
输出结果:
对小堆的操作:
#include <iostream>
#include <vector>
#include <functional>
int main()
{
vector<int> v = { 5, 7, 9, 30, 4, 1, 0, 2 };
for (const auto &e : v)
cout << e << " ";
cout << endl;
//生成一个小堆
make_heap(v.begin(), v.end(), greater<int>());
for (const auto &e : v)
cout << e << " ";
cout << endl;
sort_heap(v.begin(), v.end(), greater<int>());
for (const auto &e : v)
cout << e << " ";
cout << endl;
return 0;
}