直入主题!

1.堆

(二叉)堆是数组,可看成近似的完全二叉树。例如A[1..n]中,A[i]的父节点是A[i/2],左右孩子分别为A[2i],A[2i+1](假设都存在)。
于是可得父节点,左孩子,右孩子的下标:

Parent(i)
    return i / 2
Left(i)
    return 2 * i
Right(i)
    return 2 * i + 1

二叉堆的两种形式: 最大堆最小堆
最大堆:除了根以外的节点i都满足:
A[Parent(i)] >= A[i]
最小堆:除了根以外的节点i都满足:
A[Parent(i)] <= A[i]

2.维护堆的性质

运用Max-Heapify函数,对于每个节点i,找出它与它的左右孩子中最大的并交换。伪代码如下:

Max-Heapify(A, i) // 修改判断大小即可变为维护最小堆性质
    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 != i
        exchange A[i] with A[largest]
        Max-Heapify(A, largest) // 防止交换后largest节点不满足

可以证明在数组只有根节点的一个子节点不满足堆的性质时,运用该函数能让数组变为最大(小)堆

3.构建堆

首先引入一个性质:堆的叶的下标为n/2+1,n/2+2,...n。
根据这个性质可得:堆非叶下标为1,2,...n/2。
前n/2个节点都有子节点。
因此在构建堆时,从n/2开始向上堆建。

Build-Max-Heap(A)
    A.heap-size = A.length
    for i=A.length/2 downto 2
        Max-Heapify(A, i)

对于每一个节点i,都满足子数组的根节点至多有一个子节点不满足堆的性质,因此用Max-Heapify函数能使得该子数组成为堆。

4.堆排序

最大堆中最大的节点一定为A[1],根据这一特性来对数组排序。

Heapsort(A)
    Build-Max-Heap(A) // 构建最大堆
    for i=A.length downto 2
        exchange A[i] with A[1]
        A.heap-size = A.heap-size - 1
        Max-Heapify(A, 1)

构建最大堆后,A[1]为最大值,将其与最后一项调换,并缩减堆的大小,前i-1项满足根节点的一个子节点不满足堆的性质,用Max-Heapify函数让其成为堆,依次循环即可对A排序。
(PS:用栈可实现从大到小排序)

5.优先队列

使用堆能使优先队列的一些操作变得简单。
找出队列最大关键字:

Heap-Maximum(A)
    return A[1]

找出并删除队列最大关键字:

Heap-Extract-Max(A)
    if A.heapsize < 1
        error"heap underflow"
    max = A[1]
    A[1] = A[A.heap-size]
    A.heap-size = A.heap-size - 1
    Max-Heapify(A, 1)
    return max

去掉最大值的方法为让A[1]变为A[A.heap-size],然后缩减堆大小并建堆。
将元素i的关键字增加到key:

Heap-Increase-Key(A, i, key)
    if A[i] > key
        error
    A[i] = key
    while i > 1 and A[i] > A[Parent(i)]
        exchange A[i] with A[Parent(i)]
        i = Parent(i)

插入元素:

Max-Heap-Insert(A, key)
    A.heap-size = A.heap-size + 1
    A.[A.heap-size] = -∞
    Heap-Inscrease-Key(A, A.heap-size, key)

警告!!!以下为C++代码!!!!


堆排序:

#include<iostream>
using namespace std;
int a[100005] = {0}, n, size;
int parent(int i) //叫爸爸 
{
    return i / 2;
}
int left(int i) //左儿子 
{
    return i * 2;
}
int right(int i) //右儿子 
{
    return i * 2 + 1;
}
void Max_Heapify(int a[], int i) //让爸爸最大 
{
    int l = left(i);
    int r = right(i);
    int largest = 0;
    if(l <= size && a[l] > a[i])
        largest = l;
    else
        largest = i;
    if(r <= size && a[r] > a[largest])
        largest = r;
    if(largest != i)
    {
        swap(a[i], a[largest]);
        Max_Heapify(a, largest);
    }
}
void Build_Max_Heap(int a[]) //使数组成为最大堆 
{
    for(int i = n / 2; i >= 1; i--)
        Max_Heapify(a, i);
}
void Heapsort(int a[]) //堆排序,最大堆的根节点为堆的最大值 
{
    Build_Max_Heap(a);
    for(int i = n; i >= 2; i--)
    {
        swap(a[1], a[i]);
        size--;
        Max_Heapify(a, 1);
    }
}
int main()
{
    cin>>n;
    size = n;
    for(int i = 1; i <= n; i++)
        cin>>a[i];
    Heapsort(a);
    for(int i = 1; i <= n; i++)
        cout<<a[i]<<" ";
    return 0;
}
优先队列:
#include<iostream>
#include<cmath>
using namespace std;
int a[100005] = {0}, n, size;
int parent(int i) //叫爸爸 
{
    return i / 2;
}
int left(int i) //左儿子 
{
    return i * 2;
}
int right(int i) //右儿子 
{
    return i * 2 + 1;
}
void Max_Heapify(int a[], int i) //让爸爸最大 
{
    int l = left(i);
    int r = right(i);
    int largest = 0;
    if(l <= size && a[l] > a[i])
        largest = l;
    else
        largest = i;
    if(r <= size && a[r] > a[largest])
        largest = r;
    if(largest != i)
    {
        swap(a[i], a[largest]);
        Max_Heapify(a, largest);
    }
}
void Build_Max_Heap(int a[]) //使数组成为最大堆 
{
    for(int i = n / 2; i >= 1; i--)
        Max_Heapify(a, i);
}
void Heapsort(int a[]) //堆排序,最大堆的根节点为堆的最大值 
{
    Build_Max_Heap(a);
    for(int i = n; i >= 2; i--)
    {
        swap(a[1], a[i]);
        size--;
        Max_Heapify(a, 1);
    }
}
int Heap_Maximum(int a[]) //返回堆最大值 
{
    return a[1];
}
int Heap_Extract_Max(int a[]) //返回堆最大值并删除
{
    int max = a[1];
    a[1] = a[size];
    size--;
    Max_Heapify(a, 1);
    return max;
}
void Heap_Increase_Key(int a[], int i, int key) //让a[i]增加到key
{
    if(a[i] > key)
        cout<<"error"<<endl;
    else
    {
        a[i] = key;
        while(i > 1 && a[i] > a[parent(i)])
        {
            swap(a[i], a[parent(i)]);
            i = parent(i);
        }
    }
}
int main()
{
    cout<<"输入数组大小:"; 
    cin>>n;
    size = n;
    cout<<"输入数组元素:";
    for(int i = 1; i <= n; i++)
        cin>>a[i];
    Build_Max_Heap(a);
    for(int j = 1, i = 1; i <= n; i++)
    {
        cout<<a[i]<<" ";
        if(i == pow(2, j)-1)
        {
            cout<<endl;
            j++;
        }
    }
    cout<<endl<<"输入改变元素及值:";
    int x, y;
    cin>>x>>y;
    size = n;
    Heap_Increase_Key(a, x, y);
    for(int j = 1, i = 1; i <= n; i++)
    {
        cout<<a[i]<<" ";
        if(i == pow(2, j)-1)
        {
            cout<<endl;
            j++;
        }
    }
    cout<<endl<<"Max:"<<Heap_Maximum(a)<<endl;
    int maxi = Heap_Extract_Max(a);
    cout<<"Max:"<<maxi<<", Size:"<<size;
    return 0;
}