第六章 堆排序
总结:这章主要讲了堆、建堆、堆排序、优先级队列等。
1. 堆
堆可以被视为一颗完全二叉树,底层用数组实现。
length[A]: 数组中的元素个数
heap-size[A]: 存放在A中的堆的元素个数
树的根A[1]
给定某个结点的下标i:
父节点PARENT(i)=[i/2]
左节点LEFT(i)=2i
右节点RIGHT(i)=2i+1
最大堆:A[PARENT(i)] >= A[i]
最小堆:A[PARENT(i)] <= A[i]
2. 保持堆的性质
MAX-HEAPIFY(A, i)
输入数组A,下标i,假设以LEFT(i)和RIGHT(i)为根的两颗二叉树都是最大堆,要使以A[i]为根的二叉树也是最大堆。
分析:复杂度O(lgn)
伪代码
MAX-HEAPIFY(A, i)
l <- LEFT(i)
r <- RIGHT(i)
largest <- i
if l<=heap-size[A] and A[l]>A[largest]
then largest <- l
if r<=heap-zise[A] and A[r]>A[largest]
then largest <- r
if largest != i
then exchange A[i] <-> A[largest]
MAX-HEAPIFY(A, largest)
3. 建堆
BUILD-MAX-HEAP(A)
将数组A变为最大化堆
自底向上建堆,子数组A[(n/2)+1, …, n]中的元素都是树中的叶子
分析:复杂度O(n)
伪代码
BUILD-MAX-HEAP(A)
heap-size[A] <- length[A]
for i <- (length[A]/2) downto 1
MAX-HEAPIFY(A, i)
4. 堆排序算法HEAPSORT(A)
将A进行排序,从小到大输出
分析:O(nlgn)
伪代码
HEAPSORT(A)
BUILD-MAX-HEAP(A)
for i <- length[A] downto 2
do exchange A[1] <-> A[i]
heap-size[A] <- heap-size[A]-1
MAX-HEAPIFY(A, 1)
5. 优先队列
可以用堆实现
1) HEAP-MAXIMUM(A)
返回A中的最大值
分析:O(1)
伪代码
HEAP-MAXIMUM(A)
return A[1]
2) HEAP-EXTRACT-MAX(A)
去掉A中的最大值
分析:O(lgn)
伪代码
HEAP-EXTRACT-MAX(A)
if heap-size[A] < 1
then error “heap underflow”
max <- A[1]
A[1] <- A[heap-size[A]]
heap-size[A] <- heap-size[A]-1
MAX-HEAPIFY(A, 1)
return max
3) HEAP-INCREASE-KEY(A, i, key)
将A[i]的值增加为key,人要保持最大堆的特性
分析:O(lgn)
伪代码
HEAP-INCREASE-KEY(A, i, key)
if key < A[i]
then error “new key is smaller than the current key”
A[i] <- key
while i>1 and key > A[PARENT(i)]
do exchange A[i] <-> A[PARENT(i)]
i <- PARENT(i)
4) MAX-HEAP-INSERT(A, key)
将key插入到A
分析:O(lgn)
伪代码
MAX-HEAP-INSERT(A, key)
heap-size[A] <- heap-size[A]+1
A[heap-size[A]] <- 负无穷大
HEAP-INCREASE-KEY(A,heap-size[A],key)
最大堆的C++实现
#include <iostream> using namespace std; void exchange(int &a, int &b) { int temp=a; a=b; b=temp; } template<class T> class maxHeap { private: T *heap; int heapSize; int maxSize; public: maxHeap(int sz=10):heapSize(0),maxSize(sz){heap=new T[sz+1];} //构造函数 maxHeap(T a[],int n,int sz); //带有堆的初始值的构造函数 ~maxHeap(){delete [] heap;} void buildHeap(int n);//建立最大化堆,对大小为n void heapify(int i);//建立以下标i为根的最大化根,且假设该节点的左右子树都是最大化根 void insert(const T x); void deleteMax(); int isEmpty(){return (heapSize==0);} int isFull(){return heapSize==maxSize;} void heapSort();//堆排序,破坏了堆的特性 }; template <class T> maxHeap<T>::maxHeap(T a[], int n, int sz) { maxSize=sz; heapSize=n; heap = new T[sz+1]; for(int i=0;i<n;i++) heap[i]=a[i]; buildHeap(heapSize); } template <class T> void maxHeap<T>::heapify(int i) { int left=2*i+1; int right=2*i+2; int largest=i; if(left<heapSize && heap[largest]<heap[left]) largest=left; if(right<heapSize && heap[largest]<heap[right]) largest=right; if(largest!=i) { exchange(heap[i],heap[largest]); heapify(largest); } } template <class T> void maxHeap<T>::buildHeap(int n) { heapSize=n; for(int i=(heapSize/2);i--;i>0) heapify(i); } template <class T> void maxHeap<T>::insert(const T x) { if(isFull()) return; heapSize++; int i=heapSize-1; heap[i]=x; int parent=((i-1)/2); while(i>0 && x>heap[parent]) { exchange(heap[i],heap[parent]); i=parent; parent=((i-1)/2); } } template <class T> void maxHeap<T>::deleteMax() { if(isEmpty()) return; heap[0]=heap[heapSize-1]; heapSize--; heapify(0); } template <class T> void maxHeap<T>::heapSort() { if(isEmpty()) return; int t=heapSize; while(heapSize>0) { exchange(heap[0],heap[heapSize-1]); heapSize--; heapify(0); } for(int i=0;i<t;i++) cout << heap[i] << " "; cout << endl; } int main() { int A[10]={3,6,4,8,9,12,34,13,2,10}; maxHeap<int> h(A,10,15); h.heapSort(); h.buildHeap(10); //重新建堆 h.insert(15); h.heapSort(); h.buildHeap(11); h.deleteMax(); h.heapSort(); while(1); }