【数据结构】·堆


联系作者:humminwang@163.com

堆(heap)

堆通常是一个可以被看做一棵树的数组对象。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
堆总是满足下列性质:

  • 堆中某个节点的值总是不大于或不小于其父节点的值;
  • 堆总是一棵完全二叉树。
应用:
  • 堆排序
  • 构建优先队列
C++ STL代码:
定义方法一:
//需要调动到#include<queue>,以下以a为例:
大根堆的调用:priority_queue<int>a;
小根堆的调用:priority_queue<int,vector<int>,greater<int> > a;

定义方法二;
#include <algorithm>
//STL在<algorithm.h>中实现了对存储在数组或vector中的元素进行堆操作的函数,
//包括make_heap, pop_heap, push_heap, sort_heap
//make_heap( ):建立堆(要么大顶堆,要么小顶堆)
//push_heap( ): 在堆中添加元素
//pop_heap( ): 在堆中删除元素
//sort_heap( ): 堆排序
vector<int> min={......}
make_heap(min.begin(), min.end(), greater<int>());

//push_heap()
//要先在底层容器(数组或vector)里加入数据,再调用push_heap()。
//实现细节:(1)添加元素到vector的尾部;(2)重新调整堆。
//该算法必须是在满足堆序的条件下,添加元素。
min.push_back(15);
push_heap(min.begin(), min.end());


//pop_heap(_First, _Last,_Comp)
//实现细节:(1)删除堆顶元素;(2)用尾部元素替代max_heap[0];(3)重新调整堆。
//(pop_heap操作实际上是我们把堆顶元素取出来,放到了数组或vector容器的末尾,用原来的末尾元素去替代,然后end迭代器减1,执行siftdown()下溯函数来重新调整堆)
//注意算法执行完毕后,最大的元素并没有被取走,而是放于底层容器的末尾。如果要取走,则可以使用底部容器(vector)提供的pop_back()函数。
//pop_heap()操作后,再调用min.pop_back(),从底层容器中删掉原堆顶元素。
pop_heap(min.begin(), min.end());//取出了堆顶元素(也叫删除堆顶元素),放到了底层容器的末尾,原来末尾的元素替代堆顶,end迭代器减1,重新siftdown了堆
min.pop_back();//从底层容器(数组或vector)中删除了元素


sort_heap(_First, _Last,_Comp)
既然每次pop_heap可以获得堆顶的元素(假如是大顶堆,每次都获得最大的元素,取出放到了底层容器的末尾),那么我们持续对整个heap做pop_heap操作,每次讲操作的范围向前缩减一个元素(就是每次end迭代器减1)。最终我们可以获得一个递增的序列。
注意:这个排序是在一个堆上进行的。
sort_heap(min.begin(),min.end(), greater<int>());
堆排序细节实现C++:
#include<iostream>
using namespace std; 
void heapSort(int a[], int n);
void maxHeap(int a[], int n);
void buildMaxHeap(int a[], int n);
 
int size;
int main()
{
	int a[] = { 9, 12, -3, 0, 6, 8, 15, 7 };
	size= sizeof(a) / 4;
	heapSort(a, size);
	for (int i = 0; i < 8; i++)
		cout << a[i] << " ";
	return 0;
}
void heapSort(int a[], int n)
{
	int i;
	buildMaxHeap(a, n);
	for (i = size; i>1; i--)
	{
		swap(a[0], a[i-1]);
	    size = size - 1;
		maxHeap(a, 1);
 
 
	}
 
}
void buildMaxHeap(int a[], int n)
{
	int i = n / 2;
	for (i; i > 0; i--)
		maxHeap(a, i);
 
}
void maxHeap(int a[], int n)
{
	int leftChild, rightChild, largest;
	leftChild = 2 * n;
	rightChild = 2 * n + 1;
	int q = sizeof(a);
	if (leftChild<=size&&a[leftChild-1]>a[n-1])
		largest = leftChild;
	else
		largest = n;
	if (rightChild<=size&&a[rightChild-1]>a[largest-1])
		largest = rightChild;
	if (largest != n)
	{
		swap(a[n-1], a[largest-1]);
		maxHeap(a, largest);
	}
}

Reference:

https://blog.csdn.net/lyl771857509/article/details/78853448
https://blog.csdn.net/u013317445/article/details/89680330
https://blog.csdn.net/morewindows/article/details/6709644
https://blog.csdn.net/qq_44618728/article/details/87865748
https://www.cnblogs.com/sxkgeek/p/9662491.html
https://baike.baidu.com/item/%E5%A0%86/20606834?fr=aladdin
https://www.jianshu.com/p/6b526aa481b1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值