主要内容:
堆、最大堆、最小堆的基本概念
堆的操作:调整、创建、排序
采用堆实现优先级队列
基本概念
堆(heap)亦被称为:优先队列(priority queue)
逻辑定义:
n个元素序列{k1,k2...ki...kn},当且仅当满足下列关系时称之为堆:
(ki <= k2i,ki <= k2i+1)或者(ki >= k2i,ki >= k2i+1), (i = 1,2,3,4...n/2)
堆的实现通过构造二叉堆(binary heap),实为二叉树的一种。
性质:
1、任意节点小于或大于它的所有后裔,最小元或最大元在堆的根上(堆序性)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、斐波那契堆等。
2、堆总是一棵完全树。堆只需要满足父节点大于两个子节点,而子节点之间没有要求。作为一颗完全树,一层中的节点是从左到右填满的。如果一个节点没有左儿子,那么它一定没有右儿子。并且在第h层中如果存在节点,那么第h-1层必须是填满的。
堆的操作
调整堆
void adjust_max_heap_recursive(int *datas, int length, int i)//递归调用,最大堆调整
{
int left,right,largest;
int temp;
left = LEFT(i);//left child
right = RIGHT(i);//right child
//find the largest value among left and right and i
if(left<=length && datas[left]>datas[i]) largest = left;
else largest = i;
if(right <= length && datas[right] >datas[largest]) largest = right;
//exchange i and largest
if(largest != i)
{
temp = datas[i];
datas[i] = datas[largest];
datas[largest] = temp;
//recursive call the function, adjust from largest
adjust_max_heap(datas, length, largest);
}
}
void adjust_max_heap(int *datas,int length,int i)//非递归调用,最大堆调整
{
int left,right,largest;
int temp;
while(1)
{
left = LEFT(i); //left child
right = RIGHT(i); //right child
//find the largest value among left and rihgt and i.
if(left <= length && datas[left] > datas[i])
largest = left;
else
largest = i;
if(right <= length && datas[right] > datas[largest])
largest = right;
//exchange i and largest
if(largest != i)
{
temp = datas[i];
datas[i] = datas[largest];
datas[largest] = temp;
i = largest;
continue;
}
else
break;
}
}
创建堆
思路:逐个加入元素,调整为最大堆或最小堆,直到将所有的元素全部处理完。
void build_max_heap(int *datas,int length)//创建最大堆
{
int i;
//build max heap from the last parent node
for(i=length/2;i>0;i—)//从最后一个非叶子节点(n/2)开始到第一个非叶子(1)结束
adjust_max_heap(datas,length,i);
}
堆排序
思路:创建堆,然后从后往前调整堆。
void heap_sort(int *datas,int length)
{
int i,temp;
//bulid max heap
build_max_heap(datas,length);//创建最大堆
i=length;
//exchange the first value to the last unitl i=1
while(i>1)
{
temp = datas[i];
datas[i] = datas[1];
datas[1] =temp;
i--;
//adjust max heap,make sure the fisrt value is the largest
adjust_max_heap(datas,i,1);
}
}堆排序算法时间复杂度:调整堆过程满足递归式T(n)<=T(2n/3)+θ(1),有master定义可以知道T(n) = O(lgn),堆排序过程中执行一个循环,调用最大堆调整函数,总的时间复杂度为O(nlgn)。
优先级队列
优先级队列有两种:最大优先级队列和最小优先级队列,这两种类别分别可以用最大堆和最小堆实现。
优先级队列操作(最大优先级队列--最大堆)
插入:返回最大(优先级)元素:返回最大堆的第一个元素
最大(优先级)元素出队:删除最大堆的第一个元素,然后把最后一个移动到第一个位置,从第一个位置开始调整堆。
提高优先级:增加优先级,然后从该节点父节点开始向上调整堆。
入队:插入堆尾部,然后从该节点父节点开始向上调整堆。
优先级队列应用
实现FIFO队列:优先级递增
实现FILO栈:优先级递减