排序和顺序统计学(1)——堆排序
也有好几天没记录算法学习情况了,这两天看了《算法导论》的第二部分,排序和顺序统计学,记录一下,也顺便增强记忆
1.堆排序
就是最大堆和最小堆,用一维数组存储,数据结构是完全二叉树。主要过程分为构建最大/最小堆,插入操作,弹出最大值,取最大/最小值,改变堆中的权值。
构建堆就是从第一个非叶子节点开始,倒数到第一个节点,对于每个节点执行以下函数(最大堆为例):
void heapify(int x)
{
int largest;
if (x*2<=heapsize&&a[x] > a[x * 2]) largest = x;
else largest = x * 2;
if (x*2+1<=heapsize&&a[x * 2 + 1]>a[largest]) largest = x*2+1;
if(x!=largest)
{
swap(a[largest],a[x]);
heapify(largest);
}
}
对于每一个节点i,将它与它的两个子节点i*2和i*2+1进行比较,将最大元素放在三者中的父亲节点,并对之前存放最大元素的节点递归式用该函数,即可构建最大堆。时间复杂度为O(nlgn),对于每个元素,递归式用该函数的最大深度为lgn,每次递归时间复杂度为常数级,共对n/2个节点执行该函数,因此时间复杂度应为n/2*a*lgn,1/2及a都是常数,略去即得O(nlgn)
取最值:将堆顶元素取出即可,时间复杂度为O(1)
改变值操作:书中所说为increase函数,即对于最大堆来说,只有当值增大的时候才对其改变并进行操作,否则不进行操作。操作如下:将当前元素与他的父亲节点进行比较,若比父亲节点大则互换:
void increase(int pos,int x)
{
if(a[pos]<x)
{
a[pos] = x;
while(pos>1&&a[pos]>a[pos/2])
{
swap(a[pos],a[pos/2]);
pos = pos/2;
}
}
}//将x替换pos位置的元素
其实对于最大堆,当x<a[pos]时也是可以的,只要将调用increase函数改为调用heapify函数即可。(个人理解)
添加值:数组长度++,并将数组末尾元素设为负无穷,对该元素调用函数increase(length[a],x),length[a]为数组a的长度,x为要插入数的大小。
弹出最大值:即取最大值+删除堆顶元素。将堆顶元素与数组末尾元素互换,并对堆顶元素进行heapify操作即可
输出堆排序结果:循环length[a]次弹出最值。
以上为堆排序的各种操作。