【每日算法】堆排序

来源:互联网 发布:winpe装linux 编辑:程序博客网 时间:2024/06/01 20:13
1、堆:堆数据结构是一种数组对象。

对于表示堆的数组arr[0…n-1],我们以arr[0]为根,给定某个节点下标i,令其父节点和左右后代节点的下标为:

parent(i) = (i-1)/2;

left(i) = 2*i+1;

right(i) = 2*i+2;

这里写图片描述

堆分为最大堆和最小堆,上面就是最大堆,特点就是:除根节点以外的每个节点i,都有arr[ parent(i) ] >= arr[i]。最小堆的特点则是:除根节点以外的每个节点i,都有arr[ parent(i) ] <= arr[i]。

堆排序一般使用最大堆,最大堆中的最大元素位于根节点。

因为具有n个元素的堆是基于一颗完全二叉树的,所以其高度为O(log n)。

2、如何保持堆中的性质:

首先,我们假定以节点i的左右儿子为根的两棵二叉树都是最大堆,而以节点i为根的二叉树可能不是最大堆,则调整的过程如下:

  1. 从元素arr[i], arr[left(i)], arr[right(i)]中找出最大的元素,将下标存在largest中;
  2. 如果arr[i]是最大的,说明以节点i为根的二叉树是最大堆,无须调整,程序结束;否则,交换arr[i]和arr[largest],于是arr[i], arr[left(i)], arr[right(i)]三者满足了最大堆的性质,但是交换后,下标为largest的节点存放arr[i]的值,以该节点为根的子树又可能违反最大堆的性质,因此需要对该子树递归调用本调整过程
代码:
//arr[0...size-1]void maxHeapify(int arr[], int i, int size){    int l = left(i);    int r = right(i);    int largest = i;    if (l < size && arr[l] > arr[largest])        largest = l;    if (r < size && arr[r] > arr[largest])        largest = r;    if (largest != i)    {        exchange(arr[i], arr[largest]);        maxHeapify(arr, largest, size);    }}


3、建堆:

上面保持堆的性质是一个铺垫,它也是堆算法中的核心部分,后面我们将利用它完成建堆和堆排序。

我们先看看如何使用maxHeapify()来将一个数组arr[0…size-1]变成一个最大堆。

对于每一片树叶,我们都可以看作是一个只含一个元素的堆。于是对于叶子节点的父亲节点(左右子树都是最大堆),我们可以调用maxHeapify()来进行调整。调整之后,我们得到更大的堆,对于这些堆的父节点,我们又可以调用maxHeapify()来进行调整。

为保证maxHeapify()的调用前提,我们只需从最下面的非叶子节点开始调整,一直到根节点,整个堆建立完毕。

那么,最下面的非叶子节点的下标是多少?

在这里我只给出结论,有兴趣的读者可以尝试证明一下:

当用数组表示存储了n个元素的堆时,叶子节点的下标为:n/2, n/2+1, … , n-1。 (n/2表示向下取整)

于是我们的调整顺序为n/2-1, … , 0:

代码:

buildMaxHeap(int arr[], int size){    for (int i = size/2-1; i >= 0; --i)        maxHeapify(arr, i, size);}

4、堆排序:

为进行原地排序,我们引入另一个变量:heap_size,它用来表示堆的大小,而用size来表示数组的大小。

于是数组arr[0…size-1]中,arr[0…heap_size-1]为堆,arr[heap_size, size-1]为排好序的元素。

由最大堆的性质可知道,arr[0]存放着堆中最大的元素,于是可以利用该性质如下排序:

  1. 初始heap_size = size,调用buildMaxHeap(arr, heap_size)建立最大堆;
  2. 令i = size-1,交换arr[0]和arr[i],heap_size–,i–;
  3. 交换后,原来根的子女仍是最大堆,而根元素则可能违背了最大堆的性质,所以调用maxHeapify(arr, 0, heap_size)进行调整;
  4. 重复以上过程,直到堆的大小变为2,此时再重复一次以上过程,整个数组便从小到大排好序了。
代码:

void heapSort(int arr[], int size){    if (NULL == arr || size <= 0)        return ;    int heap_size = size;    buildMaxHeap(arr, heap_size);    for (int i = size-1; i >= 1; --i)    {        exchange(arr[0], arr[i]);        --heap_size;        maxHeapify(arr, 0, heap_size);    }}

堆排序(heapsort)的时间复杂度为O(n logn),不稳定。

原创粉丝点击