堆在本质实现上是一个数组,所有对堆的操作都是通过数组下标来实现的。但抽象来看,它可以被看成一颗近似的完全二叉树,树上的每一个节点对应数组中的一个元素。
堆分为最大堆和最小堆,它们对树上的节点提出了要求:最大堆要求父节点的元素大小大于等于子节点的大小,而最小堆则相反。上述数组经过最大堆堆化后呈现如下的树状结构:
为了访问父节点,和左右子节点,我们需要定义操作PARENT(i),LEFT(i),RIGHT(i)来根据二叉树的性质得到该节点的访问下标。在大多数计算机上,通过将i的值左移一位,LEFT过程可以在一条指令内计算得出2i。采用类似方法,在RIGHT过程也可以通过将i的值左移一位并在低位加1,快速计算2i+1。PARENT过程,则可以通过把i值右移一位的得到,可以通过宏定义实现这个过程。但值得注意的是,要满足定义的操作,数组在逻辑上是从下标1开始,编程过程中仍从下标0开始。
要实现堆排序,堆类定义了以下几个成员函数
- MAX-HEAPIFY过程:其时间复杂度位O(lgn),它是维护最大堆性质的关键。
- BUILD-MAX-HEAP过程:具有线性时间复杂度,功能是从无序的输入数组中构造一个最大堆。
- HEAPSORT过程:其时间复杂度为O(nlgn),功能是堆一个数组进行原址排序。
- MAX-HEAP-INSERT、HEAP-EXTRACT-MAX、HEAP-INCREASE-KEY和HEAP-MAXIMUM过程:时间复杂度为O(lgn),功能是利用一个堆实现一个优先队列。
C++实现:
头文件Heap.h
#ifndef __Heap_H
#define __Heap_H
#include <iostream>
#include <math.h>
using namespace std;
#define LEFT(i) i << 1
#define RIGHT(i) (i << 1) + 1
#define PARENT(i) i >> 1
#define PASSIVE_INFINITE -100000;
#define EXCHANGE(arr,a,b) \
{ \
int temp = arr[a]; \
arr[a] = arr[b]; \
arr[b] = temp; \
}
class Heap
{
public:
struct Data
{
int size;
int heap_size;
int *heap;
};
Heap(int *arr, int size)
{
data.heap = (int *)malloc(sizeof(int) * (size));//分配动态内存
for (int i = 0; i < size; i++)
data.heap[i] = *(arr + i);
data.size = size-1;//数组下标从0开始
}
void max_heapify(Data &d, int i);
void build_max_heap(Data &d);
void heap_sort(Data &d);
int heap_maximum(Data &d) { return d.heap[d.heap_size]; };
int heap_extract_max(Data &d);
void heap_increase_key(Data &d, int i, int key);
void max_heap_insert(Data &d, int key);
Data data;
};
void Heap::max_heapify(Data &d, int i)
{
int l = LEFT(i);
int r = RIGHT(i);
int largest;
if (l <= d.heap_size && d.heap[l] > d.heap[i])
largest = l;
else
largest = i;
if (r <= d.heap_size && d.heap[r] > d.heap[largest])
largest = r;
if (largest != i)
{
EXCHANGE(d.heap, i, largest);
max_heapify(d, largest);
}
}
void Heap::build_max_heap(Data &d)
{
d.heap_size = d.size;
for (int i = floor(d.size >> 1); i >= 0; i--)
max_heapify(d, i);
}
void Heap::heap_sort(Data &d)
{
build_max_heap(d);
for (int i = d.size; i >= 1; i--)
{
EXCHANGE(d.heap, 0, i);
d.heap_size = d.heap_size - 1;
max_heapify(d, 0);
}
}
/*利用堆构造优先队列定义的操作*/
int Heap::heap_extract_max(Data &d)
{
if (d.heap_size < 1)
throw "heap underflow";
int max = d.heap[d.heap_size];
d.heap[d.heap_size] = d.heap[0];
d.heap_size--;
max_heapify(d, d.heap_size);
return max;
}
void Heap::heap_increase_key(Data &d, int i, int key)
{
if(key<d.heap[i])
throw "new key is smaller than current key";
d.heap[i]=key;
while(i>1 && d.heap[PARENT(i)]<d.heap[i])
{
EXCHANGE(d.heap,i,PARENT(i));
i=PARENT(i);
}
}
void Heap::max_heap_insert(Data &d,int key)
{
d.heap_size++;
d.heap[d.heap_size]=PASSIVE_INFINITE;
heap_increase_key(d, d.heap_size, key);
}
#endif
Heap.cpp:
#include<iostream>
#include<stdlib.h>
#include<time.h>
#include"Heap.h"
using namespace std;
#define max 50
#define min -50
int* getRandData(int n) {
int *arr=(int *)malloc(sizeof(int) * n);
for (int i = 0; i < n; i++)
*(arr+i)=((rand() %(max-min+1))+min);
return arr;
}
int main()
{
srand(time(NULL));
int size=20;
int *arr=getRandData(size);//生成元素值-50~50,size大小的随机数数组
for (int i=0;i<size;i++)
cout<<*(arr+i)<<" ";
cout<<endl;
cout << "After sorted:" << endl;
Heap heap(arr,size);
heap.heap_sort(heap.data);
for (int i=0;i<size;i++)
cout << *(heap.data.heap + i) << " ";
system("pause");
return 0;
}