堆排序
参考自:链接: link
1 概念
1) 堆的基本概念
堆 是一种特殊的树,满足以下条件即为堆:
- 首先堆是一个完全二叉树
- 堆中每一个节点的值都必须大于等于(或小于等于)其左右子节点的值
- 每个节点都大于等于其子树节点的堆叫“大顶堆“或大根堆,根是最大值
- 每个节点都小于等于其子树节点的堆叫“小顶堆“或小根堆,根是最小值
因为堆的要求不像二叉搜索树那么严格。他只要求某个节点的子节点大于或小于该节点,因此同一组数据,可以构建多种不同形态的堆:
2)堆的表示
堆是完全二叉树,大部分时候都是使用数组来存储堆
规律(根节点是0号)
-
i 结点的父结点 par = floor((i-1)/2) 「向下取整」
-
i 结点的左子结点 2 * i +1
-
i 结点的右子结点 2 * i + 2
因为堆是完全二叉树,所以说,数组中的元素的父节点、孩子节点都是可以用公式算出来的!(层序遍历下)
2 堆的操作
堆的操作主要有两种:插入、删除。。(priority_queue也正是只提供了这两种方法)
不管是插入还是删除后都有可能不再满足堆的定义即:
-
堆是一颗完全二叉树
-
堆中每个节点都必须大于等于(或小于等于)其左右子节点
在插入或删除操作后需要进行调整,让其重新满足堆的特性,这个调整的过程叫做堆化(heapify)
1) 两种堆化方式
从下往上(上浮):当前元素不断向上和父节点比较大小:
- 大顶堆:当前元素比父节点大,交换,让大的节点上去
- 小顶堆:当前元素比父节点小,交换,让小的节点上去
从上往下(下沉):当前元素不断向下和两个孩子节点比较大小
- 大顶堆:当前元素与子节点中较大的比,比子节点小交换,让小的节点下去
- 小顶堆:当前元素与子节点中较小的比,比子节点大交换,让大的节点下去
当根节点是0号的时候,下沉和上浮代码是:
//模拟priority_queue
class Heap
{
private:
vector<int> vec;
int capacity;
int count;
void swapNode(int i,int j)
{
swap(vec[i],vec[j]);
}
//小根堆的上浮操作---在堆中将index节点上浮
void siftup_minheap(int index)
{
int parentNode=(index-1)/2;
while(parentNode>=0)
{
if(vec[parentNode]<vec[index])
break;//父节点比这个节点小,则停止上滤
swapNode(index,parentNode);
index=parentNode;
parentNode=(index-1)/2;
}
}
//小根堆的下沉操作--下沉的范围是[index,n),一般是vec.size()
void siftdown_minheap(int index,int n)
{
int i=index;
int j=2*i+1;//index节点的左儿子
while(j<n)
{
if(j+1<n && vec[j+1]<vec[j]