1、定义:最小堆,是一种经过排序的完全二叉树,其中任一非终端节点的数据值均不大于其左子节点和右子节点的值。
2、特性(2个):
(1)结构性:它是能用数组表示的完全二叉树。
(2)堆序性:任一结点的关键字是其子树所有结点的最大值(最大堆)或最小值(最小堆),即任意子树也应该是个堆。
3、适用:
4、实现:使用含有哨兵元素的数组实现了最小堆的创建、插入和删除,完全二叉树之所以用数组的方式存在,在于他的一个特性 若子节点为i,则父节点为(i-1)/2,若父节点为j,则子节点必为2*j+1;则在数组里面可以非常方便的通过下标去获取。
二叉堆一般使用数组来表示。请回忆一下二叉树的性质,其中有一条性质:
如果对一棵有n个节点的完全二叉树的节点按层序编号,对任一节点i有:
如果i=1 ,则节点为根节点,没有双亲。
如果2 * i > n ,则节点i没有左孩子 ;否则其左孩子节点为2i . (n为节点总数)
如果2 * i+1>n ,则节点i没有右孩子;否则其右孩子节点为21+1.
https://blog.csdn.net/qq_30163461/article/details/78681931
#include
#include
#define MinData -100//哨兵元素的值
typedef struct HeapStruct{
int *p;
int size;
int capacity; //容量
} *MinHeap;
//初始化
MinHeap Init_MinHeap(int MaxSize);
//是否装满
int IsFull(MinHeap H);
//是否为空
int IsEmpty(MinHeap H);
//插入
void Insert(MinHeap H, int data);
//删除
int Delete(MinHeap H);
//创建
void BuildMinHeap(MinHeap H, int N);
//打印
void PrintValue(MinHeap H);
#include "HeapFun.h"
//创建最小堆
void BuildMinHeap(MinHeap H, int N){
int i, num, parent, child, root, lastvalue;
if(N>H->capacity)return;
for (ing i = 1; i<= N ; i++) {
scanf_s("%d", &num);
H->p[i] = num;
}
H->size = N;
root = N/2;
while (root) {
lastvalue = H->p[root];
for (parent = root; 2 * parent <= H->size; parent = child)
{
child = 2 * parent;/*默认左结点的元素值更小*/
if (child != H->size && H->p[child + 1] < H->p[child])/*右结点元素值更小*/
child++;
if (lastvalue < H->p[child])
break;
else
H->p[parent] = H->p[child];
}
H->p[parent] = lastvalue;
--root;
}
}
//初始化最小堆:该函数给最小堆分配了内存空间并完成初始化操作,此时最小堆中元素为空。
MinHeap Init_MinHeap(int MaxSize){
MinHeap H = (MinHeap) malloc(sizeof(HeapStruct));
H->capacity = MaxSize;
H->p = (int*)malloc((MaxSize+1)*sizeof(int));
H->size = 0;
H->p[0] = MinData;
return H;
}
//插入最小堆
void Insert(MinHeap H, int data){
if(IsFull(H))return;
for (int i = ++H->size; data < H->p[i/2]; i/=2) {
H->p[i] = H->p[i/2];
}
H->p[i] = data;
}
//删除最小堆中最小元素
int Delete(MinHeap H){
if(IsEmpty(H))return ;
int minvalue , lastvalue, child, parent;
minvalue = H->p[1];
lastvalue = H->p[H->size--];
for (parent = 1; 2 * parent <= H->size; parent = child)
{
child = 2 * parent;/*默认左结点的元素值更小*/
if (child != H->size && H->p[child + 1] < H->p[child])/*若右节点的元素值更小,则调整child*/
child++;
if (lastvalue < H->p[child])
break;
else
H->p[parent] = H->p[child];
}
H->p[parent] = lastvalue;
return minvalue;
}
//打印
void PrintValue(MinHeap H){
for (int i = 1; i< H->size; i++) {
printf("%d ",H->p[i]);
}
}
//判断是否装满
int IsFull(MinHeap H){
return (H->capacity == H->size)?1:0;
}
//判断是否为空
int IsEmpty(MinHeap H){
return (0 == H->size)?1:0;
}
void main()
{
int num;
MinHeap H;
H = Init_MinHeap(100);
BuildMinHeap(H, 15);
PrintValue(H);
printf("请输入你要插入的数据:");
scanf_s("%d", &num);
Insert(H, num);
PrintValue(H);
printf("请输入你要插入的数据:");
scanf_s("%d", &num);
Insert(H, num);
PrintValue(H);
num = Delete(H);
printf("删除的元素为:%d\n", num);
PrintValue(H);
STL库中
priority_queue 容器适配器定义了一个元素有序排列的队列。默认队列头部的元素优先级最高。因为它是一个队列,所以只能访问第一个元素,这也意味着优先级最高的元素总是第一个被处理。
> 创建:
template , typename Compare=std::less> class priority_queue
//priority_queue 模板有 3 个参数,其中两个有默认的参数;第一个参数是存储对象的类型,第二个参数是存储元素的底层容器,第三个参数是函数对象,它定义了一个用来决定元素顺序的断言。
//函数对象类型 less 是一个默认的排序断言,即最大堆。fonction 中定义了 greater,即最小堆。
push(const T& obj):将obj的副本放到容器的适当位置,这通常会包含一个排序操作。
push(T&& obj):将obj放到容器的适当位置,这通常会包含一个排序操作。
emplace(T constructor a rgs...):通过调用传入参数的构造函数,在序列的适当位置构造一个T对象。为了维持优先顺序,通常需要一个排序操作。
top():返回优先级队列中第一个元素的引用。
pop():移除第一个元素。
size():返回队列中元素的个数。
empty():如果队列为空的话,返回true。
swap(priority_queue& other):和参数的元素进行交换,所包含对象的类型必须相同。
http://www.cnblogs.com/QG-whz/p/5173112.html
template
class MaxHeap
{
public:
bool insert(T val); //往二叉堆中插入元素
bool remove(T data); //移除元素
void print(); //打印堆
T getTop(); //获取堆顶元素
bool createMaxHeap(T a[], int size);//根据指定的数组来创建一个最大堆
MaxHeap(int cap = 10);
~MaxHeap();
private:
int capacity; //容量,也即是数组的大小
int size; //堆大小,也即是数组中有效元素的个数
T * heap; //底层的数组
private:
void filterUp(int index); //从index所在节点,往根节点调整堆
void filterDown(int begin ,int end ); //从begin所在节点开始,向end方向调整堆
};
/*从下到上调整堆*/
/*插入元素时候使用*/
template
void MaxHeap::filterUp(int index)
{
T value = heap[index]; //插入节点的值,图中的12
while (index > 0) //如果还未到达根节点,继续调整
{
int indexParent = (index -1)/ 2; //求其双亲节点
if (value< heap[indexParent])
break;
else
{
heap[index] = heap[indexParent];
index = indexParent;
}
}
heap[index] = value; //12插入最后的位置
};
/*插入元素*/
template
bool MaxHeap::insert(T val)
{
if (size == capacity) //如果数组已满,则返回false
return false;
heap[size] = val;
filterUp(size);
size++;
return true;
};
*从上到下调整堆*/
/*删除元素时候使用*/
template
void MaxHeap::filterDown(int current,int end)
{
int child = current * 2 + 1; //当前结点的左孩子
T value = heap[current]; //保存当前结点的值
while (child <= end)
{
if (child < end && heap[child] < heap[child+1])//选出两个孩子中较大的孩子
child++;
if (value>heap[child]) //无须调整;调整结束
break;
else
{
heap[current] = heap[child]; //孩子节点覆盖当前结点
current = child; //向下移动
child = child * 2 + 1;
}
}
heap[current] = value;
};
/*删除元素*/
template
bool MaxHeap::remove(T data)
{
if (size == 0) //如果堆是空的
return false;
int index;
for (index = 0; index < size; index++) //获取值在数组中的索引
{
if (heap[index] == data)
break;
}
if (index == size) //数组中没有该值
return false;
heap[index] = heap[size - 1]; //使用最后一个节点来代替当前结点,然后再向下调整当前结点。
filterDown(index,size--);
return true;
};
*打印大顶堆*/
template
void MaxHeap::print()
{
for (int i = 0; i < size; i++)
cout << heap[i] << " ";
};
/*获取堆顶元素*/
template
T MaxHeap::getTop()
{
if (size != 0)
return heap[0];
};
/*根据指定的数组来创建一个最大堆*/
template
bool MaxHeap::createMapHeap(T a[], int size)
{
if (size > capacity) // 堆的容量不足以创建
return false;
for (int i = 0; i < size; i++)
{
insert(a[i]);
}
return true;
};
int _tmain(int argc, _TCHAR* argv[])
{
MaxHeap heap(11);
//逐个元素构建大顶堆
for (int i = 0; i < 10; i++)
{
heap.insert(i);
}
heap.print();
cout << endl;
heap.remove(8);
heap.print();
cout << endl;
//根据指定的数组创建大顶堆
MaxHeap heap2(11);
int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
heap2.createMaxHeap(a, 10);
heap2.print();
getchar();
return 0;
}