1, 简述
堆结构是一种数组结构,它可以被视为一棵完全二叉树。
属性:元素个数(length[A]), 树的根为A[1], 给定某个节点下标i, 其父节点PARENT(i),左儿子LEFT(i),右儿子RIGHT(i).存在以一关系:
PARENT(i)= i/2;
LEFT(i) = 2i;
RIGHT(i) = 2i+1
堆应满足以下性质:
A PARENT(i)]≧A[i];
节点高度:从该节点到树的叶节点的最长向下的简单路径上边的数目。
树的高度:根节点高度。
2,堆排序
三个过程
1) heapify过程,运行时间为O(lgn),是用来维持堆性质的关键。
2) build-heap过程,以线性时间运行,可以从无序的输入数组中构造出一个堆来。
3) heapsort过程,运行时间为O(nlgn),对一个数组进程排序。
Heapify:维持当前节点与其子节点的堆性质。
Build-heap:将整个数组构建成堆,每个节点均满足堆的性质。
1 for i=length[A]/2 downto 1
Do heapify(A, i)
此过程对每个非叶节点都调用一次heapify,对各节点的处理次序保证了以某个节点i的子节点为根的子树都已成为堆后才处理i.此过程可以认为是线性时间过程,详细证明见算法导论。
Heapsort:
堆中最大元素在A[1],将A[1]与A[n]互换,并将最后一个节点去掉,将剩余元素重新构建成堆。直至堆的大小为2为止。
#include<stdio.h>
#include<stdlib.h>
#define LEFT(i) (i<<1)
#define RIGHT(i) (LEFT(i)|0x1)
#define MAX_LEN 10000
//#define MAX_LEN 100000
int array[MAX_LEN];
void heapify(int *arr,int len, int i);
void swap(int *a, int *b);
void print_array(int *arr);
void init_array(int *arr);
void build_heap(int *arr, int len);
void swap(int *a, int *b)
{
int tmp=*a; *a = *b; *b=tmp;
}
void heapify(int *arr, int len, int i)
{
int max;
if (LEFT(i)<=len&&(arr[i-1]<arr[LEFT(i)-1]))
max = LEFT(i);
else
max = i;
if (RIGHT(i)<=len&&(arr[max-1]<arr[RIGHT(i)-1]))
max = RIGHT(i);
if (max != i)
{
swap(&arr[max-1], &arr[i-1]);
heapify(arr, len, max);
}
}
void build_heap(int *arr, int len)
{
int i;
for (i=len/2; i>0; i--)
{
heapify(arr, len, i);
}
}
int main(void)
{
time_t ts1, ts2;
int len;
int i;
len = MAX_LEN;
init_array(array);
print_array(array);
time(&ts1);
build_heap(array, len);
for (i=len-1; i>0; i--)
{
swap(&array[0], &array[i]);
build_heap(array, i);
}
time(&ts2);
print_array(array);
printf("time:%lx;%lx;%lx",ts1, ts2, ts2-ts1);
return 0;
}
void init_array(int *arr)
{
int i;
int val;
for (i=0; i<MAX_LEN; i++)
arr[i] = (int)(((double)random()/RAND_MAX)*MAX_LEN);
//arr[i] = MAX_LEN-i;
}
void print_array(int *arr)
{
int i;
for (i=0; i<MAX_LEN; i++)
{
printf("%-6d", arr[i]);
if (i%20 == 0)
printf("\n");
}
printf("\n");
}