上次内容中,我们对堆有了一个大概的认识,现在,我们就来看看堆中有哪些应用吧!!!
一、优先级队列
概念:优先级队列是不同于先进先出队列的另一种队列。每次从队列中取出的是具有最高优先权的元素。
解释:优先级队列是对堆的一次封装,利用堆的性质,封装出来一个与堆类似的东西,从而达到自己的目的。
下面,直接来上代码,此处的优先级队列,依赖前面的堆的基础实现,有需要的,可以先看堆的实现有关堆的创建与实现
现在,我们来具体看下如何对堆实现一次封装,代码如下所示:
#define _CRT_SECURE_NO_WARNINGS 1
//#pragma once
#include"heap.hpp"
//优先级队列
template<class T,class Compare>
class PriorityQueue
{
public:
PriorityQueue()
{}
void Push(const T&data)
{
_hp.Push(data);
}
void Pop()
{
_hp.Pop();
}
bool Empty()const
{
return _hp.Empty();
}
size_t Size()const
{
return _hp.Size();
}
T Top()const
{
return _hp.Top();
}
private:
Heap<T, Compare> _hp;
};
void Test1()
{
PriorityQueue<int,Less<int> > q;
q.Push(2);//往堆中放入元素
q.Push(10);
q.Push(1);
cout << q.Size() << endl;
cout << q.Top() << endl;
q.Pop();//删除堆中元素
cout << q.Size() << endl;
cout << q.Top() << endl;
if (!q.Empty())//判空
cout << "非空" << endl;
else
cout << "空" << endl;
q.Pop();
cout << q.Size() << endl;
cout << q.Top() << endl;
q.Pop();//堆中只有一个元素
cout << q.Size() << endl;
cout << q.Top() << endl;
if (!q.Empty())
cout << "非空" << endl;
else
cout << "空" << endl;
q.Pop();//空堆
cout << q.Size() << endl;
cout << q.Top() << endl;
if (!q.Empty())
cout << "非空" << endl;
else
cout << "空" << endl;
}
二、堆排序
堆排序主要有两个步骤,分别为:
1、创建堆——>向下调整
升序—->大堆
降序—->小堆
2、排序(此处先默认为升序—->大堆)
在这里,排序的主要思路是:利用堆顶元素与堆中最后一个元素进行交换,则将最大的元素放置在最后,相当于这个元素已经排好,而交换后的堆有可能不符合堆的条件,则进行调整(向下调整的思路),此次的调整,排除最后一个元素,让上面的步骤不断重复,则将生成一个升序的序列。
注意:在排序中,如果为空堆与堆中只有一个元素,则都不需要进行排序。
堆排序的时间复杂度为:两次调整的时间复杂度,即N*logN+N*logN=O(N*logN)。
堆排序的代码如下所示:
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<algorithm>
#include<iostream>
using namespace std;
//升序----大堆,降序----小堆
void AdjustHeap(int *array, int size, size_t parent)
{
//默认左孩子最大
size_t child = parent * 2 + 1;
while (child < size)
{
//找最大的孩子
if (child + 1 < size&&array[child] < array[child + 1])
child = child + 1;
//交换
if (array[parent] < array[child])
{
swap(array[parent], array[child]);
parent = child;
child = parent * 2 + 1;
}
else
return;
}
}
void HeapSort(int *array, int size)
{
//创建堆
int root = (size - 1 - 1) >> 1;
for (; root >= 0; --root)
{
AdjustHeap(array, size, root);//向下调整
}
//排序
int i = 0;
for (; i < size - 1; ++i)
{
//堆顶元素与最后一个元素交换
swap(array[0], array[size - 1 - i]);
AdjustHeap(array, size - i - 1,0);
}
}
void Test2()
{
int array[] = { 53, 17, 78, 9, 45, 65, 87, 23 };
HeapSort(array, sizeof(array) / sizeof(*array));
int i = 0;
for (; i < sizeof(array) / sizeof(*array); ++i)
{
cout << array[i] << " " << endl;
}
}
但是,如果要在堆排序中,进行任意排序,即降序与升序均可,则需要一个比较器,将其定义为一个模板,则可以进行任意的排序了,具体实现如下所示:
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<iostream>
using namespace std;
template<class T>
class Last//小堆
{
public:
bool operator()(const T&left, const T&right)
{
return left < right;
}
};
template<class T>
class Most//大堆
{
public:
bool operator()(const T&left, const T&right)
{
return left > right;
}
};
template<class T, class Compare1 = Last<T>>//缺省时为小堆
class HeapSort1
{
public:
HeapSort1(T*array, size_t size)
{
//创建堆
//开辟空间
_array.resize(size);
//拷贝元素
for (int i = 0; i < size; ++i)
{
_array[i] = array[i];
}
//调整元素
int root = (size - 1 - 1) >> 1;
for (; root >= 0; --root)
{
AdjustHeap(size, root);
}
//排序
int j = 0;
for (; j < size - 1; ++j)
{
//堆顶元素与最后一个元素交换
swap(_array[0], _array[size - 1 - j]);
AdjustHeap(size - j - 1, 0);
}
}
void Print(size_t size)
{
int i = 0;
for (; i < size; ++i)
{
cout << _array[i] << " ";
}
cout << endl;
}
private:
//创建小堆-----向下调整
void AdjustHeap(int size, size_t parent)
{
//标记左孩子,且默认左孩子为最小的孩子
size_t child = parent * 2 + 1;
//找最小的孩子
while (child < size)
{
//Compare com;
if (child + 1 <size && Compare1()(_array[child + 1], _array[child]))//在此处,因为默认左孩子最小,因此要返回true,只能是这样
{
child = child + 1;//右孩子为最小
}
//比较最小的孩子与双亲的大小----值域
if (Compare1()(_array[child], _array[parent]))
{
swap(_array[parent], _array[child]);
//交换之后,可能导致孩子结点不为堆
parent = child;
child = parent * 2 + 1;
}
else
return;
}
}
private:
vector<T> _array;
};
void Test3()
{
int array[] = { 53, 17, 78, 9, 45, 65, 87, 23 };
HeapSort1<int, Most<int> > hs(array, sizeof(array) / sizeof(*array));
hs.Print(sizeof(array) / sizeof(*array));
}
至此,有关堆的应用大概就这么多,还请大家多多指教!!!
只有不停奔跑,才能不停留在原地。
1114

被折叠的 条评论
为什么被折叠?



