堆:一种完全二叉树结构
根据堆序性,分为大根堆和小根堆:
大根堆:每个父节点元素都大于它的儿子。
小根堆:每个父节点元素都小于它的儿子。
堆的存储
堆为完全二叉树,对其进行层序遍历,对每个节点进行编号(根结点编号为1)。用一维数组存储(0号位空出),下标即为节点编号,下标对应的值为节点编号对应的节点值。如下图:
堆的建立
如何将一组无序的数据建立成堆?直接对每个数编号,然后将这组数据画成完全二叉树。
显然地,
- 单节点的二叉树是堆。
- 叶子节点已经是堆了。
所以从最后一个非叶子结点(2/n)开始,依次将以2/n,2/n-1,2/n-2…为根的子树调整为堆。
for(int i = 2/n; i >= 1; i--) down(i);
堆的两种主要操作
下沉(down):当存在某个节点使得堆序性不满足,将该元素与子节点比较,交换(大根堆下沉选大儿子交换,小根堆下沉选小儿子交换),直到满足堆序性为止。
上浮(up):当存在某个节点使得堆序性不满足,直接与它的父节点比较,交换,直到满足堆序性。
以下操作以小根堆为例:
插入一个数
//size:节点编号
heap[++size] = x;//在堆的最后插入一个数
up(size);//对该元素进行一遍up操作,保持堆序性
求集合中的最小值
heap[1];//取堆顶元素即可
删除最小值
heap[1] = heap[size];//将堆中最后一个元素取代第一个元素
size--;//将最后一个元素删去(即把最小值删去)
down(1);//对堆顶元素进行一边down操作
删除任意元素
heap[k] = heap[size];//让堆最后一个元素取代第k个元素
size--;//删除第k个数
down(k); up(k);//由于大小关系不确定,干脆down一遍,up一遍,减少代码(实际上两个操作只会执行一个)
修改任意元素
heap[k] = x;
down(k); up(x);