数据结构:堆之相关操作
程序员文章站
2024-02-14 13:56:16
...
要求: 1.0 实现大小堆 2.0 用堆实现优先级队列 3.0 堆排序
1.0 大小堆的实现:
0.0 vector的相关操作为堆带来了方便,所以底层数据用Vector。
1.0 既然能用大小堆实现队列,那么堆就应该满足队列的特点:先进先出。
所以堆的pop()函数应该是堆顶弹出
2.0 为了减少代码量,用仿函数实现一个bool类型的operator()重载,在比较时就不需要写两份代码。
child+1和child比较,他们中的最大值或者最小值和parent比较,大于parent 交换(大堆),小于parent交换(小堆)
3.0 注意:建堆的时候是向下调整,执行push()操作时是需要向上调整的。
2.0 用堆实现优先级队列
优先级队列即把堆再封装了一遍,没难度。注意成员变量是堆就可以了。
pop(),push(),top(),show()。
3.0 堆排序
1.0 堆的排序只需要把排序函数封装在heap类里即可。
2.0 原理:类似于冒泡排序,每次把堆顶换下来(最大值或者最小值)
注意:每换一次,都需要固定从堆顶开始向下调整一次,调整时需要注意:循环条件size-1
否则的话堆底的最值就会被调整回去。
所以,向下调整函数需要重新写一个,多一个变量size,外层循环控制交换次数以及保留有序的尾部数据。
具体实现:
#include<iostream>
#include<vector>
#include<assert.h>
using namespace std;
//利用仿函数实现()的重载
template<class T>
struct Greater
{
bool operator()(const T& l, const T& r)
{
return l > r;
}
};
template<class T>
struct Less
{
bool operator()(const T& l, const T& r)
{
return l < r;
}
};
//堆的创建
template<class T,class compare = Less<T>>
class Heap
{
public:
Heap()
{}
Heap(T* a, int size)
{
assert(a);
_a.reserve(size); //change capacity to n (at least)
for (int i = 0; i <size;++i)
{
_a.push_back(a[i]);
}
//向下调整法,从倒数第一个非叶子结点
for (int j = (size - 2) / 2; j >= 0; --j)
{
AdjustDown(j);
}
}
void push(const T& x)
{
_a.push_back(x);
AdjustUp(_a.size()-1);
}
void pop()
{
assert(!_a.empty());
swap(_a[0], _a[_a.size()-1]);
_a.pop_back();
AdjustDown(0);
}
size_t Size()
{
return _a.size();
}
const T& top()const
{
assert(!_a.empty());
return _a[0];
}
bool empty()
{
return _a.size()== 0;
}
void show_heap()
{
for (size_t i = 0; i < _a.size(); ++i)
{
cout << _a[i] << " ";
}
cout << endl;
}
//升序调整(基础大堆)
void ascending_AdjustDown(int parent, int size)
{
int child = parent * 2 + 1;
while (child<size)
{
if (child + 1 <size && _a[child + 1]>_a[child]) //约束child+1
{
child++;
}
if (_a[child]>_a[parent])//升序排序
{
swap(_a[child], _a[parent]);
parent = child;
child = parent * 2 + 1;
}
//父节点不用换
else
break;
}
}
//堆的升序排序
void Heap_Sort(int size)
{
for (int i = (size - 2) / 2; i >= 0; --i)
{
ascending_AdjustDown(i, size);
}
for (int i = 0; i < size; ++i)
{
swap(_a[0], _a[size - 1 - i]);
ascending_AdjustDown(0, size - i - 1);
}
}
protected:
void AdjustDown(int parent)
{
int child = parent * 2 + 1;
compare com;
while (child<_a.size())
{
if (child + 1 < _a.size() && com(_a[child + 1], _a[child]) ) //约束child+1
{
child++;
}
if (com(_a[child], _a[parent]))
{
swap(_a[child], _a[parent]);
parent = child;
child = parent * 2 + 1;
}
//父节点不用换
else
break;
}
}
void AdjustUp(int child)
{
int parent = (child - 1) / 2;
compare com;
while (child>0)
{
if (com(_a[child], _a[parent]))
{
swap(_a[child], _a[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
break;
}
}
protected:
vector<T> _a;
};
//优先级队列
template<class T, class compare = Less<T>>
class PriorityQueue
{
public:
PriorityQueue(T* a, int size)
:hpp(a, size)
{}
const T& _top()const
{
return hpp.top();
}
void _push(const T& x)
{
hpp.push(x);
}
void _pop()
{
hpp.pop();
}
void _show_PriorityQueue()
{
hpp.show_heap();
}
private:
Heap<T, compare> hpp;
};
//堆排序测试
void Heap_sortTest()
{
int arr[10] = { 12, 15, 48, 1, 5, 56, 79, 54, 45, 21 };
Heap<int, Less<int> > hp(arr, sizeof(arr) / sizeof(arr[0]));
int size = hp.Size();
hp.Heap_Sort(size);
hp.show_heap();
}
//大小堆测试
void Heap_Test()
{
int arr[10] = { 12, 15, 48, 1, 5, 56, 79, 54, 45, 21 };
Heap<int, Less<int> > hp(arr, sizeof(arr) / sizeof(arr[0]));
cout << hp.Size() <<endl;
hp.show_heap();
hp.pop();
hp.show_heap();
hp.push(22);
hp.show_heap();
hp.top();
cout << hp.empty() << endl;
hp.show_heap();
cout << hp.Size() << endl;
}
void PriorityQueue_Test()
{
int arr[10] = { 12, 15, 48, 1, 5, 56, 79, 54, 45, 21 };
PriorityQueue<int, Less<int> > hp1(arr, sizeof(arr) / sizeof(arr[0]));
hp1._push(25);
hp1._show_PriorityQueue();
hp1._pop();
cout<<hp1._top()<<endl;
hp1._show_PriorityQueue();
}
int main()
{
cout <<"大小堆测试"<< endl;
Heap_Test();
cout << "优先级队列测试" << endl;
PriorityQueue_Test();
cout << "堆排序测试" << endl;
Heap_sortTest();
system("pause");
return 0;
}
结果:
下一篇: 07.svg图标