堆
1.堆排序同样具有空间原址性:任何时候都只需要常熟个额外的元素空间存储临时数据。因此,堆排序是集合了目前已经讨论的两种排序算法优点的一种排序算法
2.堆的用途:
排序
优先队列
3堆是一个数组,可以看成是一个近似的完全二叉树,树上的每个节点都对应数组的一个元素。除了最底层外,该树是完全充满的,而且是从左至右填充。
A.length通常给出数组元素的个数
A.heap-size表示有多少个堆元素存储在数组中,虽然A[1..A.length]可能都存有数据,但是只有A[1..A.heap-size]中存放的是堆的有效元素,0 <= A.heap-size <= A.length
树的根节点是A[1]
PARENT(i) ---> return i/2 的下取整
LEFT(i) ---> return 2i
RIGHT(i) ---> return 2i+1
维持堆的稳定性MAX-HEAPIFY(A, i),伪代码:
MAX-HEAPIFY(A, i){ //时间复杂度为O(h)
l = LEFT(i)
r = RIGHT(I)
if(l <= A.heap-size and A[l] > A[i])
largest = l;
else largest = i;
if(r <= A.heap-size and A[r] > A[largest])
largest = r;
if(largest != r)
exchange A[i] with A[largest]
MAX-HEAPIFY(A,largest);
}
建堆
使用MAX-HEAPIFY把一个大小为n=A.length的数组转换成最大堆。
BUILD-MAX-HEAP(A)
1.A.heap-size = A.length
2.for(i = A.length/2的下取整 to 1)
MAX-HEAPIFY(A, i)
堆排序
HEAPSORT(A)
BUILD-MAX-HEAP(A)
1 for(int i = A.length downto 2)
exchange A[1] with A[i]
A.heap-size = A.heap-size -1
MAX-HEAPIFY(A, 1);
快速排序的性能一般会优于堆排序。
代码详见如下:
//数组是从1号位开始的
int leftChild(int i){
return 2 * i;
}
int rightChild(int i){
return 2 * i + 1;
}
int parent(int i){
return i >> 1;
}
void swap(int *A, int i, int j){
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
//维持最大堆的性质
void maxHeapify(int *A, int i){
int l = leftChild(i);
int r = rightChild(i);
int largest = i;
//与左孩子比较
if (l <= heap_size && A[l] > A[largest]){
largest = l;
}
//与右孩子比较
if (r <= heap_size && A[r] > A[largest]){
largest = r;
}
//自顶向下递归
if (largest != i){
swap(A, i, largest);
maxHeapify(A, largest);
}
}
//自底向上建堆
void createMaxHeap(int *A, int length){
heap_size = length;
for (int i = heap_size >> 1; i >= 1; i--){
maxHeapify(A, i);
}
}
//堆排序
void heapsort(int *A, int length){
createMaxHeap(A, length);
for (int i = length; i >= 2; i--){
swap(A, 1, i);
heap_size--;
maxHeapify(A, 1);
}
}
优先队列:
优先队列(priority queue)是一种用来维护一组元素构成的集合S的数据结构,其中的每一个元素都有一个相关的值,成为关键字(key)。
#define MAX_QUEUE_NUM 20
template<typename T>
class MaxPriorityQueue{
public:
MaxPriorityQueue();
~MaxPriorityQueue();
bool empty(); //判断队列是否为空
T& top(); //返回最大元素
T& pop(); //删除最大元素
int length();
void push(T &t); //插入一个元素
void display(); //打印优先队列
private:
int size; //队列个数
T *K; //关键字数组
int leftChild(int i);
int rightChild(int i);
int parent(int i);
void maxHeapify(int i);
void swap(int i, int j);
};
template<typename T>
int MaxPriorityQueue<T>::length(){
return size;
}
template<typename T>
MaxPriorityQueue<T>::MaxPriorityQueue(){
K = new T[MAX_QUEUE_NUM];
size = 0;
}
template<typename T>
MaxPriorityQueue<T>::~MaxPriorityQueue(){
}
template<typename T>
bool MaxPriorityQueue<T>::empty(){
if (size > 0){
return false;
}
else{
return true;
}
}
template<typename T>
int MaxPriorityQueue<T>::leftChild(int i){
return i << 1;
}
template<typename T>
int MaxPriorityQueue<T>::rightChild(int i){
return (i << 1) + 1;
}
template<typename T>
int MaxPriorityQueue<T>::parent(int i){
return i >> 1;
}
template<typename T>
void MaxPriorityQueue<T>::swap(int i, int j){
T temp = K[i];
K[i] = K[j];
K[j] = temp;
}
template<typename T>
void MaxPriorityQueue<T>::maxHeapify(int i){
int largest = i;
int l = leftChild(i);
int r = rightChild(i);
if (l <= size && K[l] > K[largest])
largest = l;
if (r <= size && K[r] > K[largest])
largest = r;
if (largest != i){
swap(i, largest);
maxHeapify(largest);
}
}
template<typename T>
T& MaxPriorityQueue<T>::top(){
return K[1];
}
template<typename T>
T& MaxPriorityQueue<T>::pop(){
if (size < 1){
exit(0);
}
T max = K[1];
K[1] = K[size];
size--;
maxHeapify(1);
return max;
}
template<typename T>
void MaxPriorityQueue<T>::push(T &t){
size++;
K[size] = t;
int i = size;
int j = parent(i);
while (i > 1 && K[parent(i)] < t){
swap(i, parent(i));
i = parent(i);
}
}
template<typename T>
void MaxPriorityQueue<T>::display(){
int count = 1;
int index = 1;
for (int i = 1; i <= size; i++){
cout << K[i] << " ";
if (i % count == 0){
cout << endl;
count = 2 * index + count;
index++;
}
}
cout << endl;
}