排序算法之堆排序详解(附最大堆示例代码)

1.堆的概念(最大堆与最小堆)
堆排序的时间复杂度是n logN,具有nl og N时间复杂度的排序算法还有快速排序和理想状态下的归并排序,一般来说快速排序的性能优于堆排序,但堆排序在实际中也有很多的应用,后续会做具体介绍.
堆指的是堆数据结构,被看成是一个近似的完全二叉树,树上的每一个结点对应数组中的一个元素.
完全二叉树满足两个特性:
1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。
2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。
最大堆性质是指除了根以外的所有结点i都要满足:A[PARENT(i)]>=A[i];,也就是说,某个结点的值至多与其父结点一样大.,因此,堆中的最大元素存放在根结点中,并且,在任一子树种,该子树所包含的所有结点的值都不大于该子树根结点的值.
最小堆性质是指除了根以外的所有结点i都有A[PARENT]<=A[i];最小堆中的最小元素存放在根结点中.
在堆排序算法中,我们使用的是最大堆,最小堆通常用于构造优先数列.
2.堆排序原理
堆排序可分为3个步骤:
1.建堆:堆排序算法利用BUILD-MAX-HEAP将输入数组A[1..n]建成最大堆,其中n=A.length.因为数组中的最大元素总在根结点A[1]中,通过把它与A[n]进行互换,我们可以让该元素放到正确的位置
2.调整堆,因为交换之后新的根结点可能会违背最大堆的性质,为了维护最大堆的性质,我们要做的就是调用MAX-HEAP(A,1),从而在A[1,n-1]上构造一个新的最大堆
3.递归调用:堆排序算法会不断重复这一过程,直到堆的大小从n-1降到2位置终止递归调取,到此排序完成.

堆排序伪代码
调整堆
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)
建堆
BUILD-MAX-HEAP(A)
A.heap-size = A.length
for i = (A.length/2) downto 1
MAX-HEAPPIFY(A,i)
递归调用
HEAPSORT(A)
BUILD-MAX-HEAP(A)
for i = A.length downto 2
exchange A[1] with A[i]
A.heap-size = A.heap-size - 1
MAX-HEAPIFY(A,1)
3.堆排序示例代码

最大堆的java代码实现

    private static int N;

    /* Sort Function */
    //传入一个数组进行堆排序
    public static void sort(int arr[]) {
        //建堆
        heapify(arr);
        for (int i = N; i > 0; i--) {
            swap(arr, 0, i);
            N = N - 1;
            maxheap(arr, 0);
        }
    }

    //建堆的方法
    /* Function to build a heap */
    public static void heapify(int arr[]) {
        N = arr.length - 1;
        //循环调用调整堆,直到堆的大小到2为止
        for (int i = N / 2; i >= 0; i--)
            maxheap(arr, i);
    }

    //调整堆使其根结点为最大元素
    /* Function to swap largest element in heap */
    public static void maxheap(int arr[], int i) {
        int left = 2 * i;
        int right = 2 * i + 1;
        int max = i;
        if (left <= N && arr[left] > arr[i])
            max = left;
        if (right <= N && arr[right] > arr[max])
            max = right;

        if (max != i) {
            swap(arr, i, max);
            //递归调用堆的调整堆的方法
            maxheap(arr, max);
        }
    }

    /* Function to swap two numbers in an array */
    //交换数组i和j位置的元素
    public static void swap(int arr[], int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

    /* 测试方法 */
    @Test
    public void heapSortTest() {
        int arr[] = {222, 5, 2, 4, 6, 1, 3, 11, 9, 10, 8, 7, 0};
        sort(arr);
        System.out.println(Arrays.toString(arr));
    }

c++代码实现

/*
 * C++ Program to Implement Heap Sort
 */
#include <iostream>
#include <conio.h>
using namespace std;
void max_heapify(int *a, int i, int n)
{
    int j, temp;
    temp = a[i];
    j = 2*i;
    while (j <= n)
    {
        if (j < n && a[j+1] > a[j])
            j = j+1;
        if (temp > a[j])
            break;
        else if (temp <= a[j])
        {
            a[j/2] = a[j];
            j = 2*j;
        }
    }
    a[j/2] = temp;
    return;
}
void heapsort(int *a, int n)
{
    int i, temp;
    for (i = n; i >= 2; i--)
    {
        temp = a[i];
        a[i] = a[1];
        a[1] = temp;
        max_heapify(a, 1, i - 1);
    }
}
void build_maxheap(int *a, int n)
{
    int i;
    for(i = n/2; i >= 1; i--)
    {
        max_heapify(a, i, n);
    }
}
int main()
{
    int n, i, x;
    cout<<"enter no of elements of array\n";
    cin>>n;
    int a[20];
    for (i = 1; i <= n; i++)
    {
        cout<<"enter element"<<(i)<<endl;
        cin>>a[i];
    }
    build_maxheap(a,n);
    heapsort(a, n);
    cout<<"sorted output\n";
    for (i = 1; i <= n; i++)
    {
        cout<<a[i]<<endl;
    }
    getch(); 
}

测试运行结果截图

运行结果

4.优先队列简介
优先队列有两种形式:最大优先队列最小优先队列.
优先队列是一种用来维护由一组元素构成的集合S的数据结构,其中的每一个元素都有一个相关的值,成为关键字.一个最大优先队列支持一下操作:
INSERT(S,x):把元素x插入集合S中.这一操作等价于S = S U {x}.
MAXIMUM(S):返回S中具有最大关键字的元素.
EXTRACT-MAX(S):去掉并返回S中的具有最大关键字的元素.
INCREASE-KEY(S,x,k):将元素x的关键字值增加到k,这里假设k的值不小于x的原关键字值.
最大优先队列的应用有很多,其中一个就是在共享计算机系统的作业调度
最小优先队列可以用于基于事件驱动的模拟器.
在一个包含n个元素的堆中,所有优先队列的操作都可以在O(lg n)时间内完成.

如有不足之处请指正,谢谢!

附上最小堆排序的链接:http://blog.csdn.net/morewindows/article/details/6709644/
参考过别人的链接:http://www.sanfoundry.com/java-program-implement-heap-sort/

猜你喜欢

转载自blog.csdn.net/liuxu841911548/article/details/55002955
今日推荐