二叉堆 与 堆排序 算法模板

以下是视频讲解的配套代码: 戳我看超详细解析~有画图有手撕代码

文章目录

  • 二叉堆概念
  • 堆的储存
  • 插入
  • 删除
  • 查询
  • STL的优先队列
  • 堆排序
  • STL建立堆

二叉堆概念

  • 堆是一棵完全二叉树 (完全二叉树省略介绍)
  • 堆顶是最大/最小 (此处的最大最小是广义的)
  • 堆顶的左右儿子也是堆

堆的储存

由于是完全二叉树 所以直接就能用数组来进行储存

private:
	vector<T> v;
	int size;	//堆的大小 总比v大小小1 (v0是垃圾值)

并且使用

#define parent (root>>1)
#define left (root<<1)
#define right (left|1)

来获得某个节点的父亲与左右儿子 (数组下标需要从1开始)

//构造函数写一下
Heap()
{
	size = 0;
	v.push_back(T());
}

插入

  • 先push_back到堆尾 (数组末尾)
  • 不断向上进行比较交换直到到根
  • 详细看视频讲解
void push(const T &elem)
{
	size++;
	v.push_back(elem);
	int root = size;
	while (parent&&v[root] < v[parent])
	{
		swap(v[root], v[parent]);
		root = parent;
	}
}

删除

只讨论删除堆顶的 因为其他没什么意义

  • 交换堆顶和堆尾
  • 把堆尾在数组中pop_back掉
  • 从堆顶开始向下进行调整 维护堆的三个性质
    • 选左右儿子最大/最小的
    • 与之比较 直到无法交换(没有儿子 或者已经符合性质)
void pop()
	{
		swap(v[1], v[size]);
		v.pop_back();
		size--;
		int root = 1;
		while (left<=size)
		{
			int now = left;
			if (right <= size && v[right] < v[left])now = right;
			if (v[root] < v[now])break;
			swap(v[root], v[now]);
			root = now;
		}
	}

查询

直接返回1号位就行了

T top() const
	{
		return v[1];
	}

STL的优先队列

不要手写堆hh

#include
priority_queue<int> q;	//默认大顶堆
priortiy_queue<int,vector<int>,greater<int>> q;	//小顶堆 第二个模板参数是容器类型 第三个是比较

堆排序

符合以下的就能应用pop的调整方法来调整堆

  • 除了堆顶不符合堆的性质 其他都符合

那么就可以从后往前对无序数组建堆
其中heap_adjust函数就是pop里面的那个向下调整的操作

const int n;
vector<int> arr(n+1);	//待排序数组	下标从1开始
void heap_adjust(int root,int end)	//root代表当前的需要调整的节点 root+1到end 都已调整好
{
    int top=arr[root];		//当前子堆的顶端
    for(int i=2*root;i<=end;i*=2)	//更新出每个节点的左孩子
    {
        if(i<end&&arr[i]<arr[i+1])i++;	//如果左孩子比右孩子小,则选择右孩子		
        if(top>=arr[i])break;	//如果最开始的顶端比当前要大,证明已找到合适的位置插入
        arr[root]=arr[i];		//把i位置的较大值升上顶
        root=i;	//更新下当前调整到的位置
    }
    arr[root]=top;		//最后的插入
}
void build_heap()
{
    for(int i=n/2;i>0;i--)heap_adjust(i,n);	//先从后向前构建成大顶堆
}

建完堆之后:

  • 不断交换堆顶和堆尾 (因为堆顶永远最大/最小)
  • 对堆顶到堆尾-1进行调整成堆 (符合: 除了堆顶不符合堆的性质 其他都符合) 所以可以用adjust函数
  • 最后就会大顶堆生成从小到大排序 小顶堆生成从大到小排序
void heap_sort()
{
	build_heap();
    //已经建堆完成
    for(int i=n;i>1;i--){
        swap(arr[1],arr[i]);	//将堆顶和堆尾交换
        heap_adjust(1,i-1);		//把交换之后的重新调整
    }
}

STL建立堆

STL提供了

make_heap(arr.begin(),arr.end(),greater<int>());
pop_heap(arr.begin(),arr.end(),greater<int>());
arr.pop_back();
sort_heap(arr.begin(),arr.end(),greater<int>());

这几个函数来原地进行堆的操作
注意:

  • greater()的括号 生成小顶堆
  • pop_heap不会弹出元素 需要自己在容器上操作
  • sort必须在对应的大小堆上操作

你可能感兴趣的:(算法)